LeetCode 51-70题
正文
本博客记录的是 LeetCode 51 到 70 题的题解
之前很少使用的语法
string(n, '.') INT_MIN, INT_MAX // 58. Length of Last Word stringstream ssin(s); string word; int res; while (ssin >> word) res = word.size(); // 60. Permutation Sequence next_permutation(res.begin(), res.end());
# 51. N-Queens ans.append([''.join(graph[i]) for i in range(n)]) # 58. Length of Last Word len(s.rstrip().split(" ")[-1]) // 60. Permutation Sequence res.append(str(nums.pop(tk // mod))) # 63. Unique Paths II f = [[0] * (m + 1) for i in range(n + 1)] # 先 m 后 n f[i][j] = (f[i - 1][j] if i + 1 else 0) + (f[i][j - 1] if j + 1 else 0)
51. N-Queens
挺简单的 N 皇后问题,主要是 三个维度进行打表,配合 DFS遍历行
class Solution: def solveNQueens(self, n: int) -> List[List[str]]: cols = [False] * n diag = [False] * (2 * n + 10) anti_diag = [False] * (2 * n + 10) ans = [] graph = [['.'] * n for i in range(n)] def dfs(cur): if cur == n: ans.append([''.join(graph[i]) for i in range(n)]) return for i in range(n): if not cols[i] and not diag[cur - i + n] and not anti_diag[cur + i]: cols[i] = diag[cur - i + n] = anti_diag[cur + i] = True graph[cur][i] = 'Q' dfs(cur + 1) graph[cur][i] = '.' cols[i] = diag[cur - i + n] = anti_diag[cur + i] = False dfs(0) return ans
52. N-Queens II
和上一题一模一样,不过返回的数值不同,不必维护 graph 数组了
class Solution: def totalNQueens(self, n: int) -> int: cols = [False] * n diag = [False] * (2 * n + 10) anti_diag = [False] * (2 * n + 10) ans = [0] def dfs(cur): if cur == n: ans[0] += 1 return for i in range(n): if not cols[i] and not diag[cur - i + n] and not anti_diag[cur + i]: cols[i] = diag[cur - i + n] = anti_diag[cur + i] = True dfs(cur + 1) cols[i] = diag[cur - i + n] = anti_diag[cur + i] = False dfs(0) return ans[0]
53. Maximum Subarray
本题其实对应两种做法,第一种是 O(N) 的DP,第二种是简化的线段树O(nlogn)
动态规划
class Solution: def maxSubArray(self, nums: List[int]) -> int: last = res = int(-1e10) n = len(nums) for i in range(n): last = nums[i] + max(0, last) res = max(last, res) return res
线段树
没必要真正的开数组查询,这里我们仅仅只需要一次查询,所以说不需要把数组开出来。
就像是线段树中的 build函数,然后我们查询头结点的数值就可以得到结果
class Solution: def maxSubArray(self, nums: List[int]) -> int: n = len(nums) def get_max(l, r): if l == r: ret = [nums[l], nums[l], nums[l], nums[l]] else: mid = (l + r) // 2 t1 = get_max(l, mid) t2 = get_max(mid + 1, r) ret = [max(max(t1[0], t2[0]), t1[2] + t2[1]), max(t1[1], t1[3] + t2[1]), max(t2[2], t2[3] + t1[2]), t1[3] + t2[3]] return ret res = get_max(0, n - 1) return res[0]
54. Spiral Matrix
两个循环搞定,一个循环是改变方向,一个循环是沿着方向不断行走
class Solution: def spiralOrder(self, matrix: List[List[int]]) -> List[int]: n, m = len(matrix), len(matrix[0]) st = [[False] * m for i in range(n)] def check(x, y): return x >= 0 and y >= 0 and x < n and y < m dx, dy = [0, 1, 0, -1], [1, 0, -1, 0] res = [matrix[0][0]] cx, cy = 0, 0 st[0][0] = True cur_dir = -1 while len(res) != n * m: cur_dir = (cur_dir + 1) % 4 while check(cx + dx[cur_dir], cy + dy[cur_dir]) and not st[cx + dx[cur_dir]][cy + dy[cur_dir]]: cx, cy = cx + dx[cur_dir], cy + dy[cur_dir] st[cx][cy] = True res.append(matrix[cx][cy]) return res
55. Jump Game
注意我们之前证明过的 JUMP GAME II 的单调性即可
class Solution: def canJump(self, nums: List[int]) -> bool: n = len(nums) j = -1 max_idx = 0 while max_idx > j: i, j = j + 1, max_idx for k in range(i, j + 1): max_idx = max(max_idx, nums[k] + k) if max_idx >= n - 1: return True return False
更简洁的代码
class Solution: def canJump(self, nums: List[int]) -> bool: n = len(nums) j = 0 for i in range(n): if i > j: return False j = max(j, nums[i] + i) return True
56. Merge Intervals
较为简单的区间合并问题,主要是通过端点排序,然后进行贪心处理
class Solution: def merge(self, intervals: List[List[int]]) -> List[List[int]]: intervals.sort(key=lambda x: [x[0], x[1]]) res = [] n = len(intervals) pre_start = 0 max_end = -1e9 for i in range(n): if intervals[i][0] <= max_end: max_end = max(max_end, intervals[i][1]) else: if pre_start <= max_end: res.append([pre_start, max_end]) pre_start = intervals[i][0] max_end = intervals[i][1] res.append([pre_start, max_end]) return res
57. Insert Interval
和上一题类似,不过是需要自己插入排序一下
class Solution: def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]: n = len(intervals) if n == 0 or newInterval[0] > intervals[-1][0]: intervals.append(newInterval) else: for i in range(n): if intervals[i][0] >= newInterval[0]: intervals.insert(i, newInterval) break n += 1 pre_start, max_end = 0, -1e9 res = [] for i in range(n): if intervals[i][0] <= max_end: max_end = max(max_end, intervals[i][1]) else: if pre_start <= max_end: res.append([pre_start, max_end]) pre_start, max_end = intervals[i][0], intervals[i][1] res.append([pre_start, max_end]) return res
仔细读题发现 intervals
没有交集,因此我们可以将 intervals 不和 newInterval 重叠的部分放入到 res中,计算中间重叠部分的最早起点和最晚终点即可;
class Solution: def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]: n = len(intervals) res = [] k = 0 while k < n and intervals[k][1] < newInterval[0]: res.append(intervals[k]) k += 1 pre_start, max_end = newInterval[0], newInterval[1] while k < n and intervals[k][0] <= max_end: pre_start = min(pre_start, intervals[k][0]) max_end = max(max_end, intervals[k][1]) k += 1 res.append([pre_start, max_end]) while k < n: res.append(intervals[k]) k += 1 return res
58. Length of Last Word
简单的模拟题
class Solution: def lengthOfLastWord(self, s: str) -> int: n, cnt = len(s), 0 for i in range(n - 1, -1, -1): if s[i] == ' ' and cnt != 0: break cnt = cnt + 1 if s[i] != ' ' else cnt return cnt
class Solution: def lengthOfLastWord(self, s: str) -> int: return len(s.rstrip().split(" ")[-1])
有点意思的C++语法
class Solution { public: int lengthOfLastWord(string s) { stringstream ssin(s); int res = 0; string word; while (ssin >> word) res = word.size(); return res; } };
59. Spiral Matrix II
最方便的就是使用数组打表
class Solution: def generateMatrix(self, n: int) -> List[List[int]]: dx, dy = [0, 1, 0, -1], [1, 0, -1, 0] cur_dir = 0 st = [[False] * n for i in range(n)] res = [[-1] * n for i in range(n)] cx, cy = 0, 0 for i in range(n * n): st[cx][cy] = True res[cx][cy] = i + 1 nx, ny = cx + dx[cur_dir], cy + dy[cur_dir] if nx < 0 or nx >= n or ny < 0 or ny >= n or st[nx][ny]: cur_dir = (cur_dir + 1) % 4 nx, ny = cx + dx[cur_dir], cy + dy[cur_dir] cx, cy = nx, ny return res
60. Permutation Sequence
寻找排列组合的规律即可
每一个位置上,他往后的位置对应的组合数量。
class Solution: def getPermutation(self, n: int, k: int) -> str: res = [] st = [False] * 11 order = [-1 for i in range(11)] tk = k - 1 mod = 2 for i in range(n - 2, -1, -1): order[i] = tk % mod tk //= mod mod += 1 order[n - 1] = 0 for i in range(n): cnt = 0 for j in range(1, n + 1): if not st[j]: if cnt == order[i]: res.append(str(j)) st[j] = True break else: cnt += 1 return ''.join(res)
更为简洁的代码
class Solution: def getPermutation(self, n: int, k: int) -> str: res = [] nums = list(range(1, n + 1)) tk = k - 1 for i in range(n): mod = 1 for j in range(i + 1, n): mod *= (j - i) res.append(str(nums.pop(tk // mod))) tk %= mod return ''.join(res)
61. Rotate List
链表模拟,头尾相接后,查找新的头和尾
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: if not head: return head t, n = head, 0 end = None while t: n += 1 if not t.next: end = t t = t.next k %= n end.next = head t = head for i in range(0, n - 1 - k): t = t.next head = t.next t.next = None return head
62. Unique Paths
dp 求解组合数
class Solution: def uniquePaths(self, m: int, n: int) -> int: # C(m + n - 2, m - 1) # C(x, y) = C(x - 1, y) + C(x - 1, y - 1) x, y = m + n - 2, min(m - 1, n - 1) f = [[0] * (m + n + 1) for i in range(m + n + 1)] f[0][0] = 1 for i in range(1, x + 1): for j in range(x + 1): f[i][j] = f[i - 1][j] + (f[i - 1][j - 1] if j else 0) return f[x][y]
python 的大整数
class Solution: def uniquePaths(self, m: int, n: int) -> int: # C(m + n - 2, m - 1) x, y = m + n - 2, min(m - 1, n - 1) fenmu, fenzi = 1, 1 for i in range(1, y + 1): fenmu *= i fenzi *= (x - i + 1) return fenzi // fenmu
63. Unique Paths II
class Solution: def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int: n, m = len(obstacleGrid), len(obstacleGrid[0]) f = [[0] * (m + 1) for i in range(n + 1)] # 先 m 后 n f[0][0] = 1 for i in range(n): for j in range(m): if obstacleGrid[i][j]: f[i][j] = 0 elif not (i == 0 and j == 0): f[i][j] = (f[i - 1][j] if i + 1 else 0) + (f[i][j - 1] if j + 1 else 0) return f[n - 1][m - 1]
64. Minimum Path Sum
简单 DP
class Solution: def minPathSum(self, grid: List[List[int]]) -> int: n, m = len(grid), len(grid[0]) f = [[400001010] * (m + 1) for i in range(n + 1)] f[0][0] = grid[0][0] for i in range(n): for j in range(m): if not (i == 0 and j == 0): f[i][j] = grid[i][j] + min(f[i - 1][j] if i + 1 else 101010100, f[i][j - 1] if j + 1 else 101010100) return f[n - 1][m - 1]
65. Valid Number
主要是学会写函数模块,重复利用起来就好
class Solution: def check_integer(self, s:str) -> bool: if not s: return False return self.check_digits(s[1:]) if s[0] == '+' or s[0] == '-' else self.check_digits(s) def check_digits(self, s: str) -> bool: if not s: return False for i in range(len(s)): if '0' <= s[i] <= '9': continue return False return True def check_decimal_number(self, s: str) -> bool: if not s: return False s = s[1:] if s[0] == '+' or s[0] == '-' else s n, pos = len(s), -1 for i in range(n): if s[i] == '.': pos = i break if pos == -1: return False if pos == 0: return self.check_digits(s[1:]) elif pos == n - 1: return self.check_digits(s[:-1]) else: return self.check_digits(s[:pos]) and self.check_digits(s[pos+1:]) def isNumber(self, s: str) -> bool: if not s: return False pos = -1 for i in range(len(s)): if s[i] == 'e' or s[i] == 'E': pos = i break if pos != -1: return (self.check_decimal_number(s[:pos]) or self.check_integer(s[:pos])) \ and self.check_integer(s[pos + 1:]) else: return self.check_integer(s) or self.check_decimal_number(s)
66. Plus One
简单模拟即可, O(n)复杂度
class Solution: def plusOne(self, digits: List[int]) -> List[int]: n = len(digits) digits[-1] += 1 k = n - 1 while digits[k] > 9: digits[k] = 0 k -= 1 if k < 0: k = 0 digits.insert(0, 0) digits[k] += 1 return digits
67. Add Binary
模拟按位加法就可以
class Solution: def addBinary(self, a: str, b: str) -> str: a = a[::-1] b = b[::-1] n, m = len(a), len(b) if n < m: a, b = b, a n, m = m, n t = 0 res = "" for i in range(n): t += int(a[i]) if i < m: t += int(b[i]) res += str(t % 2) t //= 2 if t: res += str(t) return res[::-1]
68. Text Justification
简单的模拟题
class Solution: def fullJustify(self, words: List[str], maxWidth: int) -> List[str]: n = len(words) i = 0 res = [] while i < n: s = '' # st - ed 为双指针范围 st = i len_cnt = len(words[i]) ed = i + 1 while ed < n and len_cnt + len(words[ed]) + 1 <= maxWidth: len_cnt += len(words[ed]) + 1 ed += 1 # st --> ed - 1 为字符串范围,刚好 ed 我下一个 i 的位置 # 下面我们分配字符串 word_cnt = ed - st if ed != n: if word_cnt == 1: s = words[st] + (maxWidth - len_cnt) * ' ' else: s = words[st] len_cnt -= (word_cnt - 1) for j in range(st + 1, ed): if j - st <= (maxWidth - len_cnt) % (word_cnt - 1): s += ' ' s += ' ' * ((maxWidth - len_cnt) // (word_cnt - 1)) + words[j] else: len_cnt = len(words[st]) s = words[st] for j in range(st + 1, ed): s += ' ' + words[j] len_cnt += len(words[j]) + 1 s += (maxWidth - len_cnt) * ' ' i = ed res.append(s) return res
69. Sqrt(x)
简单二分题目
class Solution: def mySqrt(self, target: int) -> int: # 二分 x ** 2 <= target 的最大值 l, r = 0, 100010 while l < r: mid = (l + r + 1) // 2 if mid * mid <= target: l = mid else: r = mid - 1 return l
70. Climbing Stairs
斐波那契额数列做法很多
- dp 模拟
- 快速幂
- 数学公式
dp
# f[n] = f[n - 1] + f[n - 2] class Solution: def climbStairs(self, n: int) -> int: a, b = 1, 1 if n == 0 or n == 1: return 1 else: for i in range(2, n + 1): c = a + b a, b = b, c return c
矩阵快速幂
快速幂推导图示
# 2. 快速幂 class Solution: def mult(self, A, B): T = [[0, 0], [0, 0]] for i in range(2): for j in range(2): for k in range(2): T[i][j] += A[i][k] * B[k][j] return T.copy() def climbStairs(self, n: int) -> int: if n == 0 or n == 1: return 1 t = n - 1 B = [[1, 1], [1, 0]] C = [[1, 0], [0, 1]] # 单位矩阵,快速幂结束后为 B^(n-1) while t: if t % 2 == 1: C = self.mult(B, C) B = self.mult(B, B) t //= 2 A = [[1, 1], [0, 0]] C = self.mult(A, C) return C[0][0]
数学公式
但是当 n 很大时候,可能会出现精度问题
# 数学公式 class Solution: def qmi(self, x, y): res = 1.0 while y: if y % 2 == 1: res *= x x *= x y //= 2 return res def climbStairs(self, n: int) -> int: if n == 0 or n == 1: return 1 n += 1 t = 5 ** 0.5 return round((self.qmi((1 + t) / 2, n) - self.qmi((1 - t) / 2, n)) / t)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)