Leetcode 41-60 python解法
42. 接雨水
困难
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入: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. 字符串相乘
中等
给定两个以字符串形式表示的非负整数 num1
和 num2
,返回 num1
和 num2
的乘积,它们的乘积也表示为字符串形式。
**注意:**不能使用任何内置的 BigInteger 库或直接将输入转换为整数。
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
提示:
1 <= num1.length, num2.length <= 200
num1
和num2
只能由数字组成。num1
和num2
都不包含任何前导零,除了数字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
中等
给定一个长度为 n
的 0 索引整数数组 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:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]
示例 2:
输入: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:
输入: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:
输入: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. 螺旋矩阵
中等
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入: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
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
示例 1:
输入: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
时, 所有排列如下:
"123"
"132"
"213"
"231"
"312"
"321"
给定 n
和 k
,返回第 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