22.10.9 LC周赛 栈排序 + 矩阵移动(左上到右下)

CSDN话题挑战赛第2期
参赛话题:算法题解

22.10.9 LC周赛 栈排序 + 矩阵移动

   这次周赛还是做出两道题,第三道有思路但不清晰,没有找到突破口,第四道很遗憾 DFS 给忘了,一紧张想不起来了,这次将把第三题 栈排序的方法 以及第四题 矩阵移动方法 给记录一下,再接再厉。

2434. 使用机器人打印字典序最小的字符串(栈 + 巧妙预处理排序)

题目链接:2434. 使用机器人打印字典序最小的字符串
题目大意:给你一个字符串 s 和一个机器人,机器人当前有一个空字符串 t 。执行以下操作之一,直到 s 和 t 都变成空字符串:

  • 删除字符串 s 的 第一个 字符,并将该字符给机器人。机器人把这个字符添加到 t 的尾部。
  • 删除字符串 t 的 最后一个 字符,并将该字符给机器人。机器人将该字符写到纸上。
    请你返回纸上能写出的字典序最小的字符串。

例如:

输入:s = "zza"
输出:"azz"
解释:用 p 表示写出来的字符串。
一开始,p="" ,s="zza" ,t="" 。
执行第一个操作三次,得到 p="" ,s="" ,t="zza" 。
执行第二个操作三次,得到 p="azz" ,s="" ,t="" 。

输入:s = "bac"
输出:"abc"
解释:用 p 表示写出来的字符串。
执行第一个操作两次,得到 p="" ,s="c" ,t="ba" 。
执行第二个操作两次,得到 p="ab" ,s="c" ,t="" 。
执行第一个操作,得到 p="ab" ,s="" ,t="c" 。
执行第二个操作,得到 p="abc" ,s="" ,t="" 。

输入:s = "bdda"
输出:"addb"
解释:用 p 表示写出来的字符串。
一开始,p="" ,s="bdda" ,t="" 。
执行第一个操作四次,得到 p="" ,s="" ,t="bdda" 。
执行第二个操作四次,得到 p="addb" ,s="" ,t=""
  • 解题思路: 输入 预处理结果 及输出结果 一下,预处理用于获取每一个字符段的头字母。
    在这里插入图片描述

  • 时间复杂度:构造函数复杂度为 O ( N ) O(N) O(N) ,N为字符串长度

  • 空间复杂度:构造函数复杂度为 O ( N ) O(N) O(N)

class Solution:
    def robotWithString(self, s: str) -> str:
        # 经典贪心:求出栈序列的最小字典序。
        later = list(s)
        n = len(s)
        for i in range(n-2,-1,-1):
            later[i] = min(later[i],later[i+1])
        # print(s)
        ans,stack = list(),list()
        for i,ch in enumerate(s):
            while stack and stack[-1] <= later[i]:
                ans.append(stack.pop())
            stack.append(ch)
        ans += stack[::-1]
        return ''.join(ans)

62. 不同路径 (矩阵左上到右下)

题目链接:62. 不同路径
题目大意:一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
在这里插入图片描述

例如:

输入:m = 3, n = 7
输出:28
  • 解题思路:左上角 到 右下角 只走右和下 动态规划。
  • 时间复杂度: O ( M × N ) O(M×N) O(M×N),M N 分别为 矩阵的行和列
  • 空间复杂度: O ( M × N ) O(M×N) O(M×N)
class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        # 传统
        dp = [[1]*n] + [[1]+[0]*(n-1) for _ in range(m-1)]
        # print(dp))
        for i in range(1,m):
            for j in range(1,n):
                dp[i][j] = dp[i-1][j] + dp[i][j-1]
        return dp[m-1][n-1]

63. 不同路径 II(矩阵左上到右下)

题目链接:63. 不同路径 II
题目大意:一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。

例如:
在这里插入图片描述

输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
  • 解题思路:先预处理一下第一行和第一列 然后 在遍历其他位置 相对于 62. 不同路径 的区别是遇到障碍物后 continue。
  • 时间复杂度: O ( M × N ) O(M×N) O(M×N),M N 分别为 矩阵的行和列
  • 空间复杂度: O ( M × N ) O(M×N) O(M×N)
class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        m,n = len(obstacleGrid),len(obstacleGrid[0])
        dp = [[0]*n for _ in range(m)]
        for i in range(n):
            # 左上角是障碍物 直接结束
            if obstacleGrid[0][i] == 1: break
            dp[0][i] = 1
        
        for j in range(m):
            if obstacleGrid[j][0] == 1:
                break
            dp[j][0] = 1

        for i in range(1,m):
            for j in range(1,n):
                if obstacleGrid[i][j] == 1: continue
                dp[i][j] = dp[i][j-1] + dp[i-1][j]
        return dp[m-1][n-1]

980. 不同路径 III( 矩阵上下左右从a到b走完除-1外所有格)

题目链接:980. 不同路径 III
题目大意:在二维网格 grid 上,有 4 种类型的方格:

  • 1 表示起始方格。且只有一个起始方格。
  • 2 表示结束方格,且只有一个结束方格。
  • 0 表示我们可以走过的空方格。
  • -1 表示我们无法跨越的障碍。
    返回在四个方向(上、下、左、右)上行走时,从起始方格到结束方格的不同路径的数目。
    每一个无障碍方格都要通过一次,但是一条路径中不能重复通过同一个方格。

例如:

输入:[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
输出:2
解释:我们有以下两条路径:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)
2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2)

输入:[[1,0,0,0],[0,0,0,0],[0,0,0,2]]
输出:4
解释:我们有以下四条路径: 
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2),(2,3)
2. (0,0),(0,1),(1,1),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,3),(1,3),(2,3)
3. (0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(1,1),(0,1),(0,2),(0,3),(1,3),(2,3)
4. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2),(2,3)

输入:[[0,1],[2,0]]
输出:0
解释:没有一条路能完全穿过每一个空的方格一次。
请注意,起始和结束方格可以位于网格中的任意位置。
  • 解题思路:不用动态规划 回溯 老方法!
  • 时间复杂度: O ( 4 M × N ) O(4^{M×N}) O(4M×N) M和N分别为 grid 的行数和列数
  • 空间复杂度: O ( M × N ) O(M×N) O(M×N)
class Solution:
    def uniquePathsIII(self, grid: List[List[int]]) -> int:
        m,n = len(grid),len(grid[0])
        # start-(a,b) end-(c,d)
        a,b,c,d = 0,0,0,0
        step = 0
        for i,row in enumerate(grid):
            for j,val in enumerate(row):
                if val == 1: a,b = i,j
                if val == 2: c,d = i,j
                if val != -1: step += 1        
        
        self.ans = 0
        def dfs(x,y,todo):
            todo -= 1
            if x==c and y==d:
                if todo==0:
                    self.ans += 1
                return 
            # 已经走过 设置障碍物
            grid[x][y] = -1
            for nx,ny in [(x-1,y),(x+1,y),(x,y-1),(x,y+1)]:
                if 0<=nx<m and 0<=ny<n and grid[nx][ny] != -1:
                    dfs(nx,ny,todo)
            grid[x][y] = 0

        dfs(a,b,step)
        return self.ans

64. 最小路径和 (矩阵路径扩展1)

题目链接:64. 最小路径和
题目大意:给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。

例如:
在这里插入图片描述

输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 13111 的总和最小。

输入:grid = [[1,2,3],[4,5,6]]
输出:12
  • 解题思路:动态规划 不断比较右面和下面
  • 时间复杂度: O ( M × N ) O(M×N) O(M×N) M和N分别为 grid 的行数和列数
  • 空间复杂度: O ( M × N ) O(M×N) O(M×N)
class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        m,n = len(grid),len(grid[0])
        for i in range(1,m):
            grid[i][0] += grid[i-1][0]
        for j in range(1,n):
            grid[0][j] += grid[0][j-1]
        for i in range(1,m):
            for j in range(1,n):
                grid[i][j] += min(grid[i-1][j],grid[i][j-1])
        return grid[m-1][n-1]

2435. 矩阵中和能被 K 整除的路径 (矩阵路径扩展2)

题目链接:2435. 矩阵中和能被 K 整除的路径
题目大意:给你一个下标从 0 开始的 m x n 整数矩阵 grid 和一个整数 k 。你从起点 (0, 0) 出发,每一步只能往 下 或者往 右 ,你想要到达终点 (m - 1, n - 1) 。
请你返回路径和能被 k 整除的路径数目,由于答案可能很大,返回答案对 109 + 7 取余 的结果。

例如:
在这里插入图片描述

输入:grid = [[5,2,4],[3,0,5],[0,7,2]], k = 3
输出:2
解释:有两条路径满足路径上元素的和能被 k 整除。
第一条路径为上图中用红色标注的路径,和为 5 + 2 + 4 + 5 + 2 = 18 ,能被 3 整除。
第二条路径为上图中用蓝色标注的路径,和为 5 + 3 + 0 + 5 + 2 = 15 ,能被 3 整除。

在这里插入图片描述

输入:grid = [[0,0]], k = 5
输出:1
解释:红色标注的路径和为 0 + 0 = 0 ,能被 5 整除。

在这里插入图片描述

输入:grid = [[7,3,4,9],[2,3,6,2],[2,3,7,0]], k = 1
输出:10
解释:每个数字都能被 1 整除,所以每一条路径的和都能被 k 整除。
  • 解题思路:本周竞赛第四题 非常巧妙地做法啊! 由于需要遍历所有矩阵内容,由于未走到右下角,所以需要存放每一步的求余内容。
  • 时间复杂度: O ( M × N × K ) O(M×N×K) O(M×N×K) M和N分别为 grid 的行数和列数
  • 空间复杂度: O ( M × N × K ) O(M×N×K) O(M×N×K)
class Solution:
    def numberOfPaths(self, grid: List[List[int]], k: int) -> int:
        mod = 10**9+7
        m,n = len(grid),len(grid[0])
        dp = [[[0]*k for _ in range(n+1)] for _ in range(m+1)]
        dp[0][1][0] = 1
        for i,row in enumerate(grid):
            for j,x in enumerate(row):
                for v in range(k):
                    z = (x+v)%k
                    dp[i+1][j+1][z] = (dp[i+1][j+1][z]+dp[i+1][j][v]+dp[i][j+1][v])%mod
        return dp[m][n][0]

总结

   努力 奋斗!争取 AC3道。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值