Leetcode 41-60 python解法

Leetcode 41-60 python解法

42. 接雨水

困难

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

img

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

双指针

class Solution:
    def trap(self, height: List[int]) -> int:
        ans = 0
        left = 0
        right = len(height)-1
        pre = height[left]
        suf = height[right]

        while left < right:
            if pre < suf:
                ans += pre-height[left]
                left += 1
                pre = max(height[left],pre)
            else:
                ans += suf-height[right]
                right -= 1
                suf = max(height[right],suf)

        return ans                   


43. 字符串相乘

中等

给定两个以字符串形式表示的非负整数 num1num2,返回 num1num2 的乘积,它们的乘积也表示为字符串形式。

**注意:**不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

示例 1:

输入: num1 = "2", num2 = "3"
输出: "6"

示例 2:

输入: num1 = "123", num2 = "456"
输出: "56088"

提示:

  • 1 <= num1.length, num2.length <= 200
  • num1num2 只能由数字组成。
  • num1num2 都不包含任何前导零,除了数字0本身。

模拟

class Solution:
    def multiply(self, num1: str, num2: str) -> str:
        number1=0
        number2=0
        for i in range(len(num1)-1,-1,-1):
            number1+=int(num1[i])*pow(10,len(num1)-1-i)
        for j in range(len(num2)-1,-1,-1):
            number2+=int(num2[j])*pow(10,len(num2)-1-j)
        return str(number1*number2)



45. 跳跃游戏 II

中等

给定一个长度为 n0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

  • 0 <= j <= nums[i]
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

示例 1:

输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
     从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

示例 2:

输入: nums = [2,3,0,1,4]
输出: 2

提示:

  • 1 <= nums.length <= 104
  • 0 <= nums[i] <= 1000
  • 题目保证可以到达 nums[n-1]

贪心算法

class Solution:
    def jump(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return 0
        
        count = [float("inf")] * len(nums)
        count[0] = 0

        for i in range(len(nums)):
            for j in range(i + 1, min(i + nums[i] + 1, len(nums))):
                count[j] = min(count[i] + 1, count[j])

        return count[-1]



46. 全排列

中等

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]

示例 3:

输入:nums = [1]
输出:[[1]]

提示:

  • 1 <= nums.length <= 6
  • -10 <= nums[i] <= 10
  • nums 中的所有整数 互不相同

回溯型深度优先搜索

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        used = [False] * n  # 用于标记是否已使用过该位置的数
        path = []  # 当前构建的排列
        ans = []  # 存储所有的排列

        def dfs(iterator):
            if iterator == n:  # 完成一次排列
                ans.append(path.copy())  # 将当前排列加入到结果集中
                return
            
            for i in range(n):
                if not used[i]:  # 如果第i个数还没有被使用
                    used[i] = True  # 标记为已使用
                    path.append(nums[i])  # 将该数添加到当前排列
                    
                    dfs(iterator + 1)  # 递归调用以处理下一个位置
                    
                    path.pop()  # 回溯,撤销上一步的选择
                    used[i] = False  # 取消对该数的使用标记

        dfs(0)
        return ans


47. 全排列 II

中等

给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]

示例 2:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

回溯型深度优先搜索

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        if n == 0:
            return []

        ans=[]
        path=[]
        use=[False for _ in range(n)]

        def dfs(i):
            if len(path) == n and path[:] not in ans:
                ans.append(path[:])
                return

            for c in range(n):
                if use[c]==True:
                    continue
                
                path.append(nums[c])
                use[c] = True

                dfs(i+1)
                
                path.pop()
                use[c] = False

        dfs(0)
        return ans


48. 旋转图像

中等

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在** 原地** 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:

img

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

示例 2:

img

输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

提示:

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 20
  • -1000 <= matrix[i][j] <= 1000

模拟

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        n = len(matrix)
        # 转置矩阵
        for i in range(n):
            for j in range(i, n):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
        # 反转每一行
        for i in range(n):
            matrix[i].reverse()


49. 字母异位词分组

中等

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

示例 1:

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

示例 2:

输入: strs = [""]
输出: [[""]]

示例 3:

输入: strs = ["a"]
输出: [["a"]]

提示:

  • 1 <= strs.length <= 104
  • 0 <= strs[i].length <= 100
  • strs[i] 仅包含小写字母

质数哈希

prime_number   = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101]
numalpha_table = {i:j for i,j in zip("abcdefghijklmnopqrstuvwxyz",prime_number)}


class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        if len(strs)<2:
            return [strs]

        def hash_mul(string):
            result = 1
            for char in string:
                result*=numalpha_table[char]
            return result

        ans = {}
        for s in strs:
            temp = hash_mul(s)
            ans[temp] = ans.get(temp,[]) + [s]
 
        return list(ans.values())

        


50. Pow(x, n)

中等

实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000

示例 2:

输入:x = 2.10000, n = 3
输出:9.26100

示例 3:

输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25

提示:

  • -100.0 < x < 100.0
  • -231 <= n <= 231-1
  • n 是一个整数
  • 要么 x 不为零,要么 n > 0
  • -104 <= xn <= 104

快速幂

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n < 0:
            x = 1 / x
            n = -n
        
        result = 1
        while n > 0:
            if n % 2 == 1:
                result *= x
            x *= x
            n //= 2
        
        return result



51. N 皇后

困难

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。

示例 1:

img

输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

输入:n = 1
输出:[["Q"]]

提示:

  • 1 <= n <= 9

深度优先搜索

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        ans = []
        path = []

        def zero_tri(i, j, nums):
            for c in range(n):
                nums[c][j] = False
                if (c - i) + j < n:
                    nums[c][(c - i) + j] = False
                if -(c - i) + j >= 0 and -(c - i) + j < n:
                    nums[c][-(c - i) + j] = False

        def dfs(i, nums):
            if i == n:
                ans.append(path[:])
                return

            for j in range(n):
                if nums[i][j]:
                    path.append("." * j + "Q" + "." * (n - 1 - j))
                    copy_nums = [row[:] for row in nums]
                    zero_tri(i, j, nums)
                    dfs(i + 1, nums)
                    path.pop()
                    nums = copy_nums

        dfs(0, [[True for _ in range(n)] for _ in range(n)])
        return ans




52. N 皇后 II

困难

n 皇后问题 研究的是如何将 n 个皇后放置在 n × n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。

示例 1:

img

输入:n = 4
输出:2
解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

输入:n = 1
输出:1

提示:

  • 1 <= n <= 9

深度优先搜索

class Solution:
    def totalNQueens(self, n: int) -> int:
        ans = 0  # 结果计数

        # 更新nums数组,标记每一列、每一对角线的可行性
        def zero_tri(i, j, nums):
            for c in range(n):
                nums[c][j] = False  # 禁止同一列
                if (c - i) + j < n:
                    nums[c][(c - i) + j] = False  # 禁止主对角线
                if -(c - i) + j >= 0 and -(c - i) + j < n:
                    nums[c][-(c - i) + j] = False  # 禁止副对角线

        # 深度优先搜索
        def dfs(i, nums):
            nonlocal ans
            if i == n:
                ans += 1  # 找到一个解
                return

            for j in range(n):
                if nums[i][j]:  # 如果当前位置可行
                    copy_nums = [row[:] for row in nums]  # 复制nums
                    zero_tri(i, j, copy_nums)  # 更新copy_nums
                    dfs(i + 1, copy_nums)  # 递归到下一行

        # 初始化nums数组,每个位置都是可行的
        dfs(0, [[True for _ in range(n)] for _ in range(n)])
        return ans



53. 最大子数组和

中等

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

**进阶:**如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

维护最大值

# 时间复杂度O(n)
# 空间复杂度O(n)
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        ans = -inf
        min_pre_sum = pre_sum = 0
        for x in nums:
            pre_sum += x  # 当前的前缀和
            ans = max(ans, pre_sum - min_pre_sum)  # 减去前缀和的最小值
            min_pre_sum = min(min_pre_sum, pre_sum)  # 维护前缀和的最小值
        return ans


54. 螺旋矩阵

中等

给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

img

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

img

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 10
  • -100 <= matrix[i][j] <= 100

模拟

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        
        l1 = len(matrix)
        l2 = len(matrix[0])
        
        # 空矩阵或者一行/一列矩阵的情况
        if l1 == 0 or l2 == 0:
            return []
        
        used = [[False for _ in range(l2)] for _ in range(l1)]
        used[0][0] = True 
        ans = [matrix[0][0]]
        mode = [[0, 1], [1, 0], [0, -1], [-1, 0]]  # 右、下、左、上
        theta = 0  # 当前方向
        i, j = 0, 0  # 当前坐标

        def can_move(pos_i, pos_j):
            return 0 <= pos_i < l1 and 0 <= pos_j < l2 and not used[pos_i][pos_j]

        while len(ans) < l1 * l2:
            # 结束条件判定*******非常重要
            new_pos_i = i + mode[theta % 4][0]
            new_pos_j = j + mode[theta % 4][1]
            
            if can_move(new_pos_i, new_pos_j):
                ans.append(matrix[new_pos_i][new_pos_j])
                used[new_pos_i][new_pos_j] = True
                i, j = new_pos_i, new_pos_j
            else:
                # 方向无效,改变方向
                theta += 1
        
        return ans



55. 跳跃游戏

中等

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2:

输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

提示:

  • 1 <= nums.length <= 104
  • 0 <= nums[i] <= 105

贪心算法

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        n = len(nums)
        if n == 0:
            return True
        elif n == 1:
            return True
            
        _next = n-1
        for i in range(_next-1,-1,-1):
            if(nums[i]+i >= _next):
                _next = i

        return _next == 0

暴力法

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        n = len(nums)
        dp = [False for _ in range(n)]
        dp[0] = True

        for i in range(n-1):
            # 循环标记所有能跳到的地方
            if nums[i]: 
                for j in range(i+1,min(i+nums[i]+1,n)):
                    dp[j] |= dp[i]

        return dp[-1]


56. 合并区间

中等

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

提示:

  • 1 <= intervals.length <= 104
  • intervals[i].length == 2
  • 0 <= starti <= endi <= 104

Python解法

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        if len(intervals) <= 1:
            return intervals

        start  = lambda x:x[0]
        end    = lambda x:x[1]
        # 首先排序确定开始时间顺序
        intervals.sort(key = lambda x:start(x))
        result = [intervals[0]]
        
        for i in range(1,len(intervals)):
            # 大于等于都要包含,否则会错漏[1,4][4,5]这样的情况
            if end(result[-1]) >= start(intervals[i]):
                temp_result = result[-1]
                result.pop()
                # 结束时间不定,所以取最大值即可
                temp_end = max(end(intervals[i]),end(temp_result))
                result.append([start(temp_result),temp_end])
            else:
                result.append(intervals[i])

        return result 



57. 插入区间

中等

给你一个 无重叠的 *,*按照区间起始端点排序的区间列表 intervals,其中 intervals[i] = [starti, endi] 表示第 i 个区间的开始和结束,并且 intervals 按照 starti 升序排列。同样给定一个区间 newInterval = [start, end] 表示另一个区间的开始和结束。

intervals 中插入区间 newInterval,使得 intervals 依然按照 starti 升序排列,且区间之间不重叠(如果有必要的话,可以合并区间)。

返回插入之后的 intervals

注意 你不需要原地修改 intervals。你可以创建一个新数组然后返回它。

示例 1:

输入:intervals = [[1,3],[6,9]], newInterval = [2,5]
输出:[[1,5],[6,9]]

示例 2:

输入:intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出:[[1,2],[3,10],[12,16]]
解释:这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。

提示:

  • 0 <= intervals.length <= 104
  • intervals[i].length == 2
  • 0 <= starti <= endi <= 105
  • intervals 根据 starti升序 排列
  • newInterval.length == 2
  • 0 <= start <= end <= 105

Python解法

class Solution:
    def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
        if len(intervals) == 0:
            return [newInterval]

        start  = lambda x:x[0]
        end    = lambda x:x[1]
        # 首先排序确定开始时间顺序
        intervals.append(newInterval)
        intervals.sort(key = lambda x:start(x))
        result = [intervals[0]]
        
        for i in range(1,len(intervals)):
            if end(result[-1]) >= start(intervals[i]):
                temp_result = result[-1]
                result.pop()
                # 结束时间不定,所以取最大值即可
                temp_end = max(end(intervals[i]),end(temp_result))
                result.append([start(temp_result),temp_end])
            else:
                result.append(intervals[i])

        return result 


58. 最后一个单词的长度

简单

给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。

单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。

示例 1:

输入:s = "Hello World"
输出:5
解释:最后一个单词是“World”,长度为 5。

示例 2:

输入:s = "   fly me   to   the moon  "
输出:4
解释:最后一个单词是“moon”,长度为 4。

示例 3:

输入:s = "luffy is still joyboy"
输出:6
解释:最后一个单词是长度为 6 的“joyboy”。

提示:

  • 1 <= s.length <= 104
  • s 仅有英文字母和空格 ' ' 组成
  • s 中至少存在一个单词

技巧

class Solution:
    def lengthOfLastWord(self, s: str) -> int:
        return len(s.split()[-1])

模拟

class Solution:
    def lengthOfLastWord(self, s: str) -> int:
        s = list(s)
        sum_1 = 0
        for i in range(len(s) - 1, -1, -1):
            if s[i].isalpha():
                while i!=-1 and s[i].isalpha() :
                    i -= 1
                    sum_1 += 1
                break
        return sum_1



59. 螺旋矩阵 II

中等

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例 1:

img

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]

提示:

  • 1 <= n <= 20

深度优先搜索

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        mat = [[0 for _ in range(n)] for _ in range(n)]
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # right, down, left, up
        used = [[False for _ in range(n)] for _ in range(n)]
        
        def dfs(row, col, current, direction):
            mat[row][col] = current
            used[row][col] = True
            
            if current == n * n:
                return
            
            nr, nc = row + directions[direction][0], col + directions[direction][1]
            if 0 <= nr < n and 0 <= nc < n and not used[nr][nc]:
                dfs(nr, nc, current + 1, direction)
            else:
                new_direction = (direction + 1) % 4
                nr, nc = row + directions[new_direction][0], col + directions[new_direction][1]
                dfs(nr, nc, current + 1, new_direction)
        
        dfs(0, 0, 1, 0)
        return mat


60. 排列序列

困难

给出集合 [1,2,3,...,n],其所有元素共有 n! 种排列。

按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

给定 nk,返回第 k 个排列。

示例 1:

输入:n = 3, k = 3
输出:"213"

示例 2:

输入:n = 4, k = 9
输出:"2314"

示例 3:

输入:n = 3, k = 1
输出:"123"

提示:

  • 1 <= n <= 9
  • 1 <= k <= n!

python 栈实现

0ms 击败100.00%

class Solution:
    def getPermutation(self, n: int, k: int) -> str:
        @cache
        def factorial(n):
            if n == 0 or n == 1: 
                return 1
            return n * factorial(n -1)

        k = k - 1
        arange = list(range(n + 1))
        offset = n - 1 # 初始化偏移量
        s = "" # 初始化字符串

        while offset:
            div, k = divmod(k, factorial(offset))
            tmp = arange[1 + div]
            s += str(tmp)
            arange.remove(tmp)
            offset -= 1
        else:
            # 最后一轮自动跳出时
            s += str(arange[1])

        return s    


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值