leetcode题解python版:71-75

71、简化路径

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径
请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。
解:用栈存储,’…‘则pop,’.‘和’/'则不管,遇到单词则加入。最后再把stack中的元素连接到一起。

class Solution:
    def simplifyPath(self, path: str) -> str:
        path=path.strip('/').split('/')
        n=len(path)
        stack=[]
        for s in path:
            if s=='..':
                if stack:
                    stack.pop()
            elif s=='.' or s=='':
                pass
            else:
                stack.append(s)
        return '/'+'/'.join(stack)

执行用时:40 ms, 在所有 Python3 提交中击败了84.89%的用户
内存消耗:13.5 MB, 在所有 Python3 提交中击败了89.08%的用户

72、编辑距离

给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符

解法一:该题最先想到的方法就是BFS,只要进行一定程度的遍历就能找到结果,但是该方法会超时,而且很难进行改进,在这里也不提了。
解法二:字符串相关问题一定要想到动态规划。该题是无法用一维动态规划去解决的,因此需要用二维动态规划去解决。关键是状态转移如何去解决。
令dp[i][j]为word1的前i个与word2的前j个字母匹配的最少操作次数。
这里首次要理解的是三种操作分别作用再1和2的情况
在word1中插入一个字符相当于在word2中删除一个字符。
在word1中删除等价于在word2中插入
在word1中替换相当于在word2中替换
由上述分析我们可以将6中操作化为3种操作,在word1中插入,在word2中插入,在word1中替换。这样的话我们每进行一次操作单词数量不会减少,这是可以进行动态规划的基础。
现在考虑递归表达式,对dp[i][j]考虑word1和word2的最后一个字母,如果相同,我们可以不做操作,直接处理dp[i-1][j-1],如果不相同势必要进行上述三种操作之一,如果是word1最后插入一个相同的,则变为dp[i][j-1],在word2插入则变为dp[i-1][j],在word1中替换,则变成dp[i-1][j-1].
综上:if word1[i-1]==word2[j-1],dp[i][j]=dp[i-1][j-1],
否则dp[i][j]=1+min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])。
最后再讨论初值dp[0][0]=0,dp[i][0]=i,dp[0][j]=j

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        n = len(word1)
        m = len(word2)
        if n * m == 0:
            return n + m
        dp=[[0 for _ in range(m+1)] for _ in range(n + 1)]
        for i in range(n + 1):
            dp[i][0] = i
        for j in range(m + 1):
            dp[0][j] = j
        for i in range(1, n + 1):
            for j in range(1, m + 1):
                if word1[i-1]!=word2[j-1]:
                    dp[i][j]=1+min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])
                else:
                    dp[i][j]=dp[i-1][j-1] 
        return dp[n][m]

执行用时:204 ms, 在所有 Python3 提交中击败了66.16%的用户
内存消耗:17.5 MB, 在所有 Python3 提交中击败了12.68%的用户

73、矩阵置零

给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
解法一:朴素的想法就是先记录再去变零,就是这样的话效率还可以接受

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        m=len(matrix)
        n=len(matrix[0])
        col=[]
        row=[]
        for i in range(m):
            haveZero=False
            for j in range(n):
                if matrix[i][j]==0:
                    if j not in col:
                        col.append(j)
                    if not haveZero:
                        haveZero=True
                        row.append(i)
        for i in range(m):
            if i in row:
                matrix[i]=[0 for _ in range(n)]
            else:
                for j in range(n):
                    if j in col:
                        matrix[i][j]=0

执行用时:52 ms, 在所有 Python3 提交中击败了67.59%的用户
内存消耗:14.1 MB, 在所有 Python3 提交中击败了61.13%的用户

74、搜索二维矩阵

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
解:高效的话肯定要用二分法的思路来进行。把矩阵拉长成为一个数组,用二分法即可。

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix or not matrix[0]:
            return False
        m=len(matrix)
        n=len(matrix[0])
        left=0
        right=m*n-1
        while left<right:
            mid=(right+left)//2
            a=matrix[mid//n][mid%n]
            if a==target:
                return True
            elif a<target:
                if mid+1>right:
                    return False
                else:
                    left=mid+1
            else:
                if mid-1<left:
                    return False
                else:
                    right=mid-1
        if matrix[left//n][left%n]==target:
            return True
        else:
            return False

执行用时:40 ms, 在所有 Python3 提交中击败了77.88%的用户
内存消耗:14.5 MB, 在所有 Python3 提交中击败了83.38%的用户

75、颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
解法一:原地排序如果想要快一点可以用归并排序,但是归并排序需要O(n)的额外空间,并不是一个好的选择,这里还是写了下来。

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        def mergeSort(nums):
            if len(nums)>1:
                mid=len(nums)//2
                lefthalf=nums[:mid]
                righthalf=nums[mid:]
                mergeSort(lefthalf)
                mergeSort(righthalf)
                i=j=k=0
                while i<mid and j<len(nums)-mid:#拉链式插入
                    if lefthalf[i]<righthalf[j]:
                        nums[k]=lefthalf[i]
                        k=k+1
                        i=i+1
                    else:
                        nums[k]=righthalf[j]
                        k=k+1
                        j=j+1
                while i<len(lefthalf):
                    nums[k]=lefthalf[i]
                    i=i+1
                    k=k+1
                while j<len(righthalf):
                    nums[k]=righthalf[j]
                    j=j+1
                    k=k+1
        mergeSort(nums)

执行用时:36 ms, 在所有 Python3 提交中击败了88.83%的用户
内存消耗:13.7 MB, 在所有 Python3 提交中击败了22.55%的用户
可以看出归并排序的速度确实快,但内存占用偏高。

解法二:事实上由于本题的特殊性(一共就三种不同的数),用双指针进行遍历和交换可以达到O(n)的速度,且只要常数级的存储空间。左指针的左侧是全零区域(遇到零可以和左指针的数交换),右指针的右侧是全二的区域,中间是待查区域。只是这样遇到1就很难处理,因此可以用第三个指针负责遍历,之前的两个指针纯粹用来标记边界。

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        i=k=0
        n=len(nums)
        if n==0:
            return []
        j=n-1
        while k<=j:
            if nums[k]==0:
                if k!=i:
                    temp=nums[k]
                    nums[k]=nums[i]
                    nums[i]=temp
                k=k+1
                i=i+1
            elif nums[k]==2:#j和它交换来的可能是0,因此k不能向前走,而i和k交换来已经被扫过,不含1和2,因此k可以向前走
                temp=nums[k]
                nums[k]=nums[j]
                nums[j]=temp
                j=j-1
            else:
                k=k+1

执行用时:36 ms, 在所有 Python3 提交中击败了88.83%的用户
内存消耗:13.7 MB在所有 Python3 提交中击败了26.55%的用户

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值