首页 > 其他分享 >【LeetCode 2684】矩阵中移动的最大次数

【LeetCode 2684】矩阵中移动的最大次数

时间:2024-03-18 12:34:52浏览次数:25  
标签:int 矩阵 col grid 2684 next true LeetCode dp

题目描述

原题链接: 2684 矩阵中移动的最大次数

解题思路

  • 每次只能向右侧的下一列紧挨着的三行严格大的格子移动;
  • 能移动到i列代表能移动i次, 这取决于i-1列可到达的矩阵位置的状态, 即可以整列递推相邻列是否可移动到达;
  • 两个方向递推的思路:
    • 三个(col+1)位置的状态可以逆推出一个(col)位置状态, 即可以视为从右往左移动到严格小的位置来求解;
    • 正常从左到右递推, 由(col)位置状态来确定三个(col+1)位置状态, 这种思路会重复处理(col+1)位置;
  • 题解和提交结果图中有递归解法的代码, 思路是一样的就没自己写了。
    PS: 第一个逆序思路是起床后边吃早饭边写完提交的, 不知道为什么会就想着逆序了, 当时吃完早饭要出门也就没多想。 回家后第二天想着继续优化一下换成正常从左到右递推, 又陷入递推一推三时会出现重复处理(col+1)位置的牛角尖, 直到整理这篇思路文字时才想明白完全也能从左到右三推一来防止重复, 只能说即使已经解决的题目最后再整理一篇简单随笔也说不定有新的收获了~

解题代码

  • 初次提交通过的逆序递推版本:

      /**
       * 按列逆序DP
       * 执行用时: 15 ms , 在所有 Java 提交中击败了 41.30% 的用户
       * 内存消耗: 55.30 MB , 在所有 Java 提交中击败了 18.12% 的用户
       */
      public int maxMoves(int[][] grid) {
          int m = grid.length, n = grid[0].length;
          int ans = 0;
          int[] dp = new int[m];
          int[] tmp = new int[m];
          for (int col = n - 2; col >= 0; col--) {
              // 处理grid[0][col]
              if (grid[0][col] < grid[0][col + 1]) {
                  tmp[0] = dp[0] + 1;
              }
              if (grid[0][col] < grid[1][col + 1]) {
                  tmp[0] = Math.max(tmp[0], dp[1] + 1);
              }
              for (int row = 1; row < m - 1; row++) {
                  for (int i = -1; i < 2; i++) {
                      if (grid[row][col] < grid[row + i][col + 1]) {
                          tmp[row] = Math.max(tmp[row], dp[row + i] + 1);
                      }
                  }
              }
              if (grid[m - 1][col] < grid[m - 1][col + 1]) {
                  tmp[m - 1] = dp[m - 1] + 1;
              }
              if (grid[m - 1][col] < grid[m - 2][col + 1]) {
                  tmp[m - 1] = Math.max(tmp[m - 1], dp[m - 2] + 1);
              }
              dp = tmp;
              tmp = new int[m];
          }
          for (int i = 0; i < m; i++) {
              ans = Math.max(ans, dp[i]);
          }
          return ans;
      }
    
  • 从左到右递推, 借助next数据忽略重复的(col+1)位置:

      /**
       * 用Boolean数组从左到右处理DP数据
       * 执行用时: 3 ms , 在所有 Java 提交中击败了 93.49% 的用户
       * 内存消耗: 53.64 MB , 在所有 Java 提交中击败了 96.74% 的用户
       */
      public int maxMoves(int[][] grid) {
          int m = grid.length, n = grid[0].length;
          boolean[] dp = new boolean[m];// dp[i] 表示是否可以移动到当前列的i行位置
          for (int i = 0; i < m; i++) {
              dp[i] = true;
          }
          boolean[] next = new boolean[m];
          for (int col = 0; col < n - 1; col++) {
              boolean moveNext = false;
              for (int i = 0; i < m; i++) {
                  if (!dp[i]) {
                      continue;
                  }
                  int val = grid[i][col];
                  if (i > 0 && !next[i - 1] && grid[i - 1][col + 1] > val) {
                      next[i - 1] = true;
                      moveNext = true;
                  }
                  if (!next[i] && grid[i][col + 1] > val) {
                      next[i] = true;
                      moveNext = true;
                  }
                  if (i < m - 1 && !next[i + 1] && grid[i + 1][col + 1] > val) {
                      next[i + 1] = true;
                      moveNext = true;
                  }
              }
              if (!moveNext) {// 当前列所有行都不能继续移动,直接返回结果
                  return col;
              }
              dp = next;
              next = new boolean[m];
          }
          return n - 1;
      }
    
  • 从左到右递推, 但是不用考虑下一列会重复判断的情况(整理随笔内容时才想到写出来的版本):

      /**
       * 从左到右递推, 由(row-1, col)、(row, col)和(row+1, col)来确定(row, col+1), 不用考虑下一列重复判断
       * 执行用时: 2 ms , 在所有 Java 提交中击败了 99.70% 的用户
       * 内存消耗: 53.97 MB , 在所有 Java 提交中击败了 74.00% 的用户
       */
      public int maxMoves6(int[][] grid) {
          int m = grid.length, n = grid[0].length;
          boolean[] dp = new boolean[m];// dp[i] 表示是否可以移动到当前列的i行位置
          for (int i = 0; i < m; i++) {
              dp[i] = true;
          }
          boolean[] next = new boolean[m];
          for (int col = 0; col < n - 1; col++) {
              boolean moveNext = false;
              // 递推next[0]状态
              if ((dp[0] && grid[0][col + 1] > grid[0][col]) || (dp[1] && grid[0][col + 1] > grid[1][col])) {
                  next[0] = true;
                  moveNext = true;
              }
              // 递推next[1...m-1]状态
              for (int i = 1; i < m - 1; i++) {
                  int val = grid[i][col + 1];
                  if ((dp[i - 1] && val > grid[i - 1][col]) || (dp[i] && val > grid[i][col]) || (dp[i + 1] && val > grid[i + 1][col])) {
                      next[i] = true;
                      moveNext = true;
                  }
              }
              // 递推next[m-1]状态
              if ((dp[m - 2] && grid[m - 1][col + 1] > grid[m - 2][col]) || (dp[m - 1] && grid[m - 1][col + 1] > grid[m - 1][col])) {
                  next[m - 1] = true;
                  moveNext = true;
              }
              if (!moveNext) {// 当前列所有行都不能继续移动,直接返回结果
                  return col;
              }
              dp = next;
              next = new boolean[m];
          }
          return n - 1;
      }
    

标签:int,矩阵,col,grid,2684,next,true,LeetCode,dp
From: https://www.cnblogs.com/coding-memory/p/18080098

相关文章

  • 代码随想录算法训练营第十天|LeetCode 20.有效的括号、1047.删除字符串中的所有相邻重
    20.有效的括号题目链接:https://leetcode.cn/problems/valid-parentheses/description/解题思路:题目转化:三种类型的括号,需要做匹配匹配规则是:左右括号的类型要匹配、数量要一致,而且要按照顺序匹配例子是:“()”、“(){}[]”、“(([]))”条件转化:按照顺序匹配:......
  • leetcode 21 合并两个有序链表
    https://www.bilibili.com/video/BV1xa411A76q?p=4&vd_source=cdfcf738e0429ec2cffe4778dd8dd0e4 #迭代#https://blog.csdn.net/m0_61661179/article/details/127205244classSolution:defmergeTwoLists(self,list1:Optional[ListNode],list2:Optional[List......
  • LeetCode精选101刷题必备(C++)-附详细分类及解体说明
    分享一本leetcode刷题必备,互联网就业必备的免费书,非常好,值得推荐。感谢作者高畅无私整理和免费分享。本书介绍    本书分为算法和数据结构两大部分,又细分了十五个章节,详细讲解了刷LeetCode时常用的技巧。我把题目精简到了101道,一是呼应了本书的标题,二是不想让读......
  • LeetCode题练习与总结:有效的数独
    一、题目请你判断一个 9x9的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)注意:一个有效的数独(......
  • LeetCode题练习与总结:搜索插入位置
    一、题目给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为O(logn)的算法。二、解题思路初始化两个指针,left指向数组的起始位置,right指向数组的结束位置。当left小于等......
  • LeetCode 7 / 100
    哈希表、双指针哈希表两数之和字母异位词分组最长连续序列双指针移动零盛最多水的容器三数之和接雨水LeetCode1.两数之和LeetCode49.字母异位词分组LeetCode128.最长连续序列LeetCode[283.移动零](https://leetcode.cn/problems/move-zeroes/?envType=st......
  • Leetcode刷题-动态规划
    爬楼梯链接:70.爬楼梯-力扣(LeetCode)假设你正在爬楼梯。需要n阶你才能到达楼顶。每次你可以爬1或2个台阶。你有多少种不同的方法可以爬到楼顶呢?示例1:输入:n=2输出:2解释:有两种方法可以爬到楼顶。1.1阶+1阶2.2阶示例2:输入:n=3输出:3解释:有三种方法可......
  • LeetCode2024年3月14日每日一题(2789. 合并后数组中的最大元素)
    这里写目录标题单调栈代码的核心逻辑如下:单调栈单调栈是一种特殊的数据结构,它在算法设计中被广泛使用,尤其是在处理与栈相关的问题时,如括号匹配、最长有效括号子串、最小窗口子串等。单调栈的核心思想是栈内的元素保持某种单调性(递增或递减),这使得它在处理特定问题时比......
  • 奇怪的回溯增加了 | leetcode131分割回文串
    题目要求:给你一个字符串s,请你将s分割成一些子串,使每个子串都是回文串。返回s所有可能的分割方案示例1:输入:s="aab"输出:[["a","a","b"],["aa","b"]]示例2:输入:s="a"输出:[["a"]]上述为常规做法,这里回溯的时候是i+1的,就很正常 这是我第一次做的时候自己憋出来......
  • LeetCode 992. K 个不同整数的子数组
    解题思路举一个例子可能会比较好理解nums=[1,2,1,2,3],k=2i表示的是右指针,j表示的是左指针。i=3时,需要求出符合子数组中含有k个不同整数,此时的j1=0需要求出符合子数组中含有k-1个不同整数,此时的j2=1j1~j2之间就是符合子数组中含有k个不同整数的子数组个数。相......