Leetcode刷题记录71-80,python语言

71 简化路径

定义一个函数simplifyPath来简化Unix风格的文件路径,参数为原始路径path。
使用栈来存储简化后的路径。
将原始路径按’/‘分割成目录名列表。
遍历目录名列表,处理每个目录名:
如果目录名为空或为当前目录’.‘,则忽略;
如果目录名为上级目录’…‘,则弹出栈顶目录;
其他情况,将目录名压入栈中。
将栈中的目录名用’/‘连接起来形成简化后的路径。
在简化后的路径前面添加’/'。
返回简化后的路径。

class Solution:
    def simplifyPath(self, path: str) -> str:
        # 使用栈来存储简化路径
        stack = []
        # 将路径按'/'分割成目录名列表
        dirs = path.split('/')
        
        # 遍历目录名列表
        for directory in dirs:
            # 忽略空目录名或当前目录'.'
            if directory == '' or directory == '.':
                continue
            # 如果目录名为上级目录'..',则弹出栈顶目录
            elif directory == '..':
                if stack: # stack不为空
                    stack.pop()
            # 其他情况,压入栈中
            else:
                stack.append(directory)
        
        # 将栈中的目录名用'/'连接起来形成简化后的路径
        simplified_path = '/' + '/'.join(stack)
        
        # 返回简化后的路径
        return simplified_path
        

72 编辑距离

定义一个函数minDistance来计算将word1转换成word2所使用的最少操作数,参数为两个单词word1和word2。
获取word1和word2的长度。
初始化一个动态规划矩阵dp,其中dp[i][j]表示将word1的前i个字符转换成word2的前j个字符所需的最少操作数。
初始化边界条件:
当word1为空时,插入word2的所有字符;
当word2为空时,删除word1的所有字符。
使用动态规划求解,遍历word1和word2的每个字符:
如果当前字符相等,则不需要操作,继承前一状态的操作数;
否则,考虑插入、删除、替换操作中的最小操作数,并加上当前操作。
最终dp[m][n]即为将word1转换成word2所使用的最少操作数。
返回最少操作数。

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
         # 获取两个单词的长度
        m, n = len(word1), len(word2)
        
        # 初始化动态规划矩阵,dp[i][j]表示将word1的前i个字符转换成word2的前j个字符所需的最少操作数
        dp = [[0] * (n + 1) for _ in range(m + 1)]
        
        # 初始化边界条件
        for i in range(m + 1): # 当word1为空时,插入word2的所有字符。循环取不到m+1
            dp[i][0] = i # 挨个插入
        for j in range(n + 1): # 当word2为空时,删除word1的所有字符。循环取不到n+1
            dp[0][j] = j # 挨个删除,需要的最小操作数
        
        # 动态规划求解
        for i in range(1, m + 1): # 从1开始到m
            for j in range(1, n + 1):
                # 如果word1的第i个字符与word2的第j个字符相等,则不需要操作,继承前一状态的操作数
                if word1[i - 1] == word2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1]
                # 否则,考虑插入、删除、替换操作中的最小操作数,并加上当前操作
                else:
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1 # dp[i - 1][j]是表示插入,dp[i][j - 1]删除word2的j;dp[i - 1][j - 1]是替换
        
        # 返回word1转换成word2所使用的最少操作数
        return dp[m][n]

73 矩阵置零

定义一个函数setZeroes来实现矩阵置零,参数为一个二维矩阵matrix。
获取矩阵的行数和列数。
定义两个标记变量row_zero和col_zero,用来标记第一行和第一列是否需要置零,初始化为False。
检查第一行和第一列是否有0,并更新对应的标记变量。
遍历矩阵的除第一行和第一列外的所有元素,如果某个元素为0,则将对应的行和列的第一个元素置零,作为标记。
根据标记,将对应行和列的剩余元素置零。
如果第一行或第一列需要置零,则将第一行或第一列的所有元素置零。
完成矩阵置零。

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        # 获取矩阵的行数和列数
        m, n = len(matrix), len(matrix[0])
        
        # 定义两个标记变量,用来标记第一行和第一列是否需要置零
        row_zero, col_zero = False, False
        
        # 检查第一行是否有0
        for j in range(n): #对第一行每列遍历
            if matrix[0][j] == 0:
                row_zero = True
                break # 直接退出for整个循环
        
        # 检查第一列是否有0
        for i in range(m): # 对第一列每行元素遍历
            if matrix[i][0] == 0:
                col_zero = True
                break
        
        # 遍历矩阵,将出现0的行和列的第一个元素置零
        for i in range(1, m): # 从1开始,第二行第二列那个元素,从左往右循环
            for j in range(1, n):
                if matrix[i][j] == 0: # 如果当前元素为0,
                    matrix[i][0] = 0 # 该行的第一列令为0,算作打个标记 。只改变第一行或者第一列的对应元素。不然还要写多个for循环,复杂度大
                    matrix[0][j] = 0 
        
        # 根据第一列的标记,将对应行置零
        for i in range(1, m): 
            if matrix[i][0] == 0:
                for j in range(1, n):
                    matrix[i][j] = 0
        
        # 根据第一行的标记,将对应列置零
        for j in range(1, n):
            if matrix[0][j] == 0:
                for i in range(1, m):
                    matrix[i][j] = 0
        
        # 如果第一行或第一列需要置零,则将第一行或第一列置零
        if row_zero:
            for j in range(n):
                matrix[0][j] = 0 # 第一行的所有列令为0
        if col_zero:
            for i in range(m):
                matrix[i][0] = 0

74 搜索二维矩阵

定义一个函数searchMatrix来判断矩阵中是否存在目标值,参数为二维矩阵matrix和目标值target。
首先检查矩阵是否为空,如果为空则直接返回False。
获取矩阵的行数和列数。
初始化二分查找的左右边界,左边界为0,右边界为行数乘以列数减1。
进行二分查找,直到左边界大于右边界。
在每一次循环中,计算中间元素的索引mid,并获取对应的元素值mid_val。
如果mid_val等于目标值target,则返回True。
如果mid_val小于目标值target,则将左边界更新为mid + 1。
如果mid_val大于目标值target,则将右边界更新为mid - 1。
如果循环结束仍然没有找到目标值,则返回False。

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix or not matrix[0]: # 矩阵为空
            return False
        
        rows, cols = len(matrix), len(matrix[0])
        
        # 初始化行和列的左右边界
        left, right = 0, rows * cols - 1 # 所有元素的最后一位
        
        # 二分查找 
        while left <= right: # 左右指针
            mid = (left + right) // 2 # 取商的整数部分,4.5取4。矩阵从大到小排序的
            mid_val = matrix[mid // cols][mid % cols] # 矩阵对应值,mid // cols整数除法表示在第几行;mid % cols 余数,表示第几列,整除了cols后
            if mid_val == target:
                return True
            elif mid_val < target: # 目标值更大,更新左指针
                left = mid + 1
            else:
                right = mid - 1
        
        return False

75 颜色分类

定义一个函数sortColors来对颜色数组进行排序,参数为颜色数组nums。
初始化三个指针:curr表示当前遍历到的位置,red表示红色区域的右边界,blue表示蓝色区域的左边界。
遍历数组,直到当前位置超过蓝色区域的左边界。
如果当前元素为红色(0),则将当前元素与红色区域的右边界交换,并向后移动当前指针和红色区域的右边界。
如果当前元素为蓝色(2),则将当前元素与蓝色区域的左边界交换,并向前移动蓝色区域的左边界。
如果当前元素为白色(1),则只需要向后移动当前指针,不需要交换元素。
排序完成后,数组中红色元素在前,白色元素在中,蓝色元素在后。
返回排序后的数组。

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
         # 初始化三个指针,分别指向当前遍历到的位置,红色的右边界和蓝色的左边界
        curr, red, blue = 0, 0, len(nums) - 1 # 蓝色的左边界为末尾的,红色的右边界为开头;这两个中间区域为白色
        
        # 遍历数组,直到当前位置超过蓝色的左边界
        while curr <= blue:
            if nums[curr] == 0:  # 如果当前元素为红色, 为零
                nums[curr], nums[red] = nums[red], nums[curr]  # 将当前元素与红色区域的右边界交换
                curr += 1  # 向后移动当前指针和红色区域的右边界
                red += 1
            elif nums[curr] == 2:  # 如果当前元素为蓝色
                nums[curr], nums[blue] = nums[blue], nums[curr]  # 将当前元素与蓝色区域的左边界交换
                blue -= 1  # 向前移动蓝色区域的左边界, 说明蓝色的元素增加一个,curr不动
            else:  # 如果当前元素为白色
                curr += 1  # 只需要向后移动当前指针,不需要交换元素
        
        # 排序完成后,数组中红色元素在前,白色元素在中,蓝色元素在后
        return nums

77 组合

定义一个函数combine来生成所有可能的组合,参数为整数n和k,分别表示数字范围和组合长度。
在函数内部定义一个辅助函数backtrack来进行递归生成组合,参数为当前数字start和当前已经生成的组合path。
如果当前组合的长度等于k,将其添加到结果集中,并返回。
遍历从start到n的数字,依次尝试将每个数字添加到组合中。
将当前数字添加到组合中后,递归调用backtrack函数,继续向后添加数字。
在递归返回后,进行回溯操作,将当前数字从组合中移出,继续尝试下一个数字。
最终返回结果集中存储的所有可能的组合。

# 代码随想录:k层数,第一层n个选择,第二层每个节点展开变少,因为只往右选
class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        def backtrack(start, path): # path为当前一个小组合,list组合结果
            if len(path) == k:  # 如果当前组合的长度等于k,将其添加到结果集中
                res.append(path[:])
                return
            for i in range(start, n + 1):  # 遍历从start到n的数字, 注意写的n+1
                path.append(i)  # 将当前数字添加到组合中
                backtrack(i + 1, path)  # 递归调用,继续向后添加数字 ;树结构的第二层
                path.pop()  # 回溯,将当前数字移出组合;
            
        res = []  # 用于存储结果集
        backtrack(1, [])  # 从数字1开始递归生成组合
        return res

78 子集

定义一个函数subsets来生成数组的所有子集,参数为整数数组nums。
在函数内部定义一个辅助函数backtrack来进行递归生成子集,参数为当前遍历的起始位置start和当前已经生成的子集path。
将当前子集添加到结果集中,即空集是任何集合的子集,因此将空集添加到结果中。
从start位置开始遍历nums数组,依次尝试将每个元素添加到子集中。
将当前元素添加到子集中后,递归调用backtrack函数,继续向后生成子集。
在递归返回后,进行回溯操作,将当前元素从子集中移出,继续尝试下一个元素。
最终返回结果集中存储的所有可能的子集。

class Solution:
	def subsets(nums):
	    def backtrack(start, path):
	        res.append(path[:])  # 将当前子集添加到结果集中
	        for i in range(start, len(nums)):  # 从start位置开始遍历nums数组
	            path.append(nums[i])  # 将当前元素添加到子集中
	            backtrack(i + 1, path)  # 递归调用,继续向后生成子集
	            path.pop()  # 回溯,将当前元素移出子集
	        
	    res = []  # 用于存储结果集
	    backtrack(0, [])  # 从数组的第一个元素开始递归生成子集
	    return res

79 单词搜索

定义一个函数exist来判断给定单词是否存在于二维网格中,参数为二维网格board和目标单词word。
在函数内部定义一个辅助函数backtrack来进行回溯搜索,参数为当前位置的行索引i、列索引j和单词中的字母索引k。
如果当前位置越界或当前字母不匹配目标单词中的字母,则返回False。
如果已经匹配到目标单词的最后一个字母,则返回True。
标记当前位置已访问,并尝试向当前位置的上、下、左、右四个相邻位置继续搜索。
如果其中任意一个方向搜索到了匹配的单词,返回True。
回溯完成后,还原当前位置的字母,并返回搜索结果。
遍历整个二维网格,对每个位置调用backtrack函数进行搜索,如果存在匹配的单词则返回True,否则返回False。

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        def backtrack(i, j, k): #当前位置的行索引i、列索引j和单词中的字母索引k。
            # 如果索引越界或者当前字母不匹配,返回False
            if not (0 <= i < len(board) and 0 <= j < len(board[0])) or board[i][j] != word[k]:
                return False
            # 如果单词的所有字母都匹配,返回True
            if k == len(word) - 1:
                return True
            # 标记当前位置已访问
            temp, board[i][j] = board[i][j], '/'
            # 检查当前位置的上、下、左、右四个相邻位置,这里相当于 检查树结构下一层
            res = (backtrack(i + 1, j, k + 1) or
                backtrack(i - 1, j, k + 1) or
                backtrack(i, j + 1, k + 1) or
                backtrack(i, j - 1, k + 1))
            # 还原当前位置的字母
            board[i][j] = temp
            return res

        # 遍历整个二维网格,寻找是否存在单词
        for i in range(len(board)):
            for j in range(len(board[0])):
                if backtrack(i, j, 0): # 如果为真,返回true
                    return True
        return False

80 删除有序数组中的重复项

定义函数removeDuplicates来删除排序数组中的重复项,参数为排序后的数组nums。
如果数组长度小于等于2,无需进行修改,直接返回数组长度。
使用快慢指针来标记数组中不重复元素的位置。初始化慢指针为2,表示前两个元素必定保留。
从第三个元素开始遍历数组,使用快指针。
如果当前元素与慢指针之前的第二个元素不相等,则说明当前元素是新的不重复元素,需要保留。
将当前元素移到慢指针位置,并更新慢指针。
遍历完成后,慢指针的位置即为修改后数组的长度。
返回修改后数组的长度。

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        if len(nums) <= 2:
            return len(nums)
        
        # 定义快慢指针,快指针用于遍历数组,慢指针用于标记不重复元素的位置
        slow = 2 # 初始化慢指针为2,表示前两个元素必定保留。
        for fast in range(2, len(nums)):
            # 如果当前元素与慢指针之前的第二个元素不相等,则说明当前元素是新的不重复元素
            if nums[fast] != nums[slow - 2]: # 只允许同一数字只出现两次,!=不等于表示该数字没有出现第三次,满足要求。nums是有序数组。
                # 将当前元素移到慢指针位置,并更新慢指针
                nums[slow] = nums[fast]
                slow += 1
        
        return slow

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值