说明
各位码友好,此文章仅记录自己在力扣上的刷题笔记,写的非常简略,外人看不一定好理解,若有耽搁各位码友的时间,还请见谅。
文章目录
- 说明
- 1. 两数之和
- 2. 两数相加
- 3. 无重复字符的最长子串
- 4. 寻找两个正序数组的中位数
- 5. 最长回文子串
- 6. Z字型变换(赞)
- 8. 字符串转换整数
- 9. 回文数
- 11.盛最多水的容器(赞)
- 12. 整数转罗马数字
- 13. 罗马数字转整数
- 15 三数之和_中等
- 16 最接近的三数之和_中等
- 17. 电话号码的字母组合
- 18. 四数之和
- 19. 删除链表的倒数第 N 个结点(赞)
- 20. 有效的括号(赞)
- 21. 合并两个有序链表
- 22. 括号生成(赞)
- 23. 合并K个升序链表
- 24. 两两交换链表中的节点
- 25.K个一组翻转链表
- 26. 删除有序数组中的重复项
- 28. 实现strStr()
- 思想1: KMP(字符串匹配算法)
- 思想2: 使用库函数 return haystack.index(needle) if needle in haystack else -1
- 29. 两数相除( 非常重要!!!!,一定要看题解 )
- 30.串联所有单词的子串——(很重要!!!!)
- 31.下一个排列
- 32. 最长有效括号(很有想法!!!)
- 34. 在排序数组中查找元素的第一个和最后一个位置
- 36. 有效的数独
- 38.外观数列
- 39. 组合总和
- 40. 组合综合Ⅱ(!!!)
- 41. 缺失的第一个正数
- 42. 接雨水
- 43. 字符串相乘
- 46. 全排列
- 47.全排类Ⅱ
- 思想:位运算标记+回溯+列表去重
- 48. 旋转图像
- 53. 最大子数组和(很重要!!!)
- 54. 螺旋矩阵(思想非常奇妙!)
- 55. 跳跃游戏
- 59. 螺旋矩阵
- 思想:定义上下左右边界,然后循环遍历
- 61. 旋转链表
- 62. 不同路径
- 73. 矩阵置零
- 102. 二叉树的层序遍历
- 77.组合(从[1, n]中选出所有k个数的组合)**
- 82. 删除有序链表中的重复元素
1. 两数之和
(1)知识点
思路: 通过字典用保存原数组的值和索引。
(3)结果
2. 两数相加
思路:递归求解
(2)结果
3. 无重复字符的最长子串
思想——滑动窗口,维护一个窗口,记录窗口最左边的索引、当前最长长度、当前窗口长度。若已存在新准备要进入窗口的字符,则通过while循环从窗口左边一直移除,移除到没有新准备进入窗口的字符时,为止。
(2)结果
4. 寻找两个正序数组的中位数
思路
从小到大依次遍历,使用right保留当前数值,left保留前一个数;共遍历 (len1+len2) / 2次;
如果len是奇数,返回right; 如果是偶数,返回(right+left)/ 2;如果是奇数,返回right。
这里有个非常重要的边界分析思想:当只有两种情况时,将其中一种情况的边界全部分析完,然后剩下的就是另外一种情况了。
(2)结果
5. 最长回文子串
思路:分为两种情况,分别为回文个数为奇数或偶数
我的思路非常简洁:分为两种情况,分别为回文个数为奇数或偶数;
当个数为奇数时:把每一个字符都当作中间点,向两边延伸,记录最长的回文字符串个数以及中间点的索引;
当个数为偶数时: 把每一个字符都当作最中间的两个数字的左边那一个,然后向两边延申,记录最长和中间点索引,最后返回最长的那个回文串。
(2)结果
6. Z字型变换(赞)
思路:看图,很有意思
(2)结果
8. 字符串转换整数
9. 回文数
思想: 将数字转换程字符串,然后前后对照即可
(2)结果
11.盛最多水的容器(赞)
思想:从前后两端进行比较,每次移动,其底都会减1,此时,如移动长板子,则面积一定会减小(因为高是由短板子决定的,此时底又减少了1,所以面积一定减少);若移动短板子,面积可能增大、减少、不变。
所以如果想求最大面积,每次移动短板子即可
(2)代码
12. 整数转罗马数字
(1)思想
此题最重要的思想就是将所有的 整数和罗马数字全部罗列出来,然后再进行穷举即可。
(2)代码
13. 罗马数字转整数
思想:主要在于理解罗马数字的构成:罗马数字序列中,如果:左边的数字 < 右边的数字,那么前面累加的和应该减去左边的数字;反之,则加
tips:
注意图中:
索引-1: 表示取最后一个元素
(2)代码
15 三数之和_中等
思想: 排序、双指针找数、去重
Step1: 排序
Step2:双指针找数
Step3:去重
(2)代码:
16 最接近的三数之和_中等
思想: 排序、两边往中间跑
Step1: 先排序
Step2:从中间向两边跑
(2)代码
17. 电话号码的字母组合
思想:递归获取每一个数字对应的字母
(2)代码
18. 四数之和
同三数之和差不多,代码如下:
19. 删除链表的倒数第 N 个结点(赞)
思路: 前后(pre、end)双指针,先使其间隔n个节点、再同步前进是end指针指向最后一个节点。此时,pre.next即为因删除的节点。正常删除即可
代码即结果:
20. 有效的括号(赞)
思想:字典+栈(好好看看python中字典和栈的运用)
代码:
21. 合并两个有序链表
思路:遍历选取链头节点最小值,然后被选节点前移
22. 括号生成(赞)
思路:深度优先搜索,先添加左括号,后添加右括号
代码
23. 合并K个升序链表
思想:和21题一样,遍历选取链头节点最小值,然后被选节点前移
代码:
24. 两两交换链表中的节点
思想:画图找到规律,然后while循环
代码:
25.K个一组翻转链表
思路:找到k个一组的起始点,翻转链表,然后重置节点,进行循环
代码:
class Solution:
def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
if head == None or k == 1:
return head
count = 1
node1 = head
node2 = head
# 1.找到新链头节点
while node2 != None and count < k:
node2 = node2.next
count += 1
if node2 == None:
return head
newHead = node2
count = 1
while node2!= node1:
# 2.标记后两个起始点
node3 = node2.next
node4 = node3
while node4!= None and count < k:
node4 = node4.next
count += 1
if node4 == None:
node4 = node3
# 3.反转链表
if k == 2:
node2.next = node1
else:
cur = node1
mid = cur.next
end = mid.next
while end != node2:
mid.next = cur
cur = mid
mid = end
end = end.next
end.next = mid
mid.next = cur
# 4. 重置节点,方便循环
node1.next = node4
node1 = node3
node2 = node4
count = 1
return newHead
26. 删除有序数组中的重复项
思路:前后p、q双指针,若有不同,p前移
代码:
28. 实现strStr()
思想1: KMP(字符串匹配算法)
思想2: 使用库函数 return haystack.index(needle) if needle in haystack else -1
代码:
29. 两数相除( 非常重要!!!!,一定要看题解 )
思想: 除法越界、位运算
题解(一定要看题解): 题解
30.串联所有单词的子串——(很重要!!!!)
思路:窗口滑动+哈希
代码:
31.下一个排列
思想:从后数,找到一个比后面一个数小的位置i,然后从最后数找到比nums[i]大一点的值,然后较换,最后将位置i之后的值进行逆置。
代码:
32. 最长有效括号(很有想法!!!)
思想: 通过栈保存未被匹配的索引,最后计算栈中索引的最大间隔
34. 在排序数组中查找元素的第一个和最后一个位置
思想:两次二分查找,一次寻找第一次target出现的索引,第2次寻找最后一个target出现的索引
36. 有效的数独
思想:分别新建行列以及block标记,然后在遍历原数组
代码如下:
38.外观数列
思想:遍历生成
39. 组合总和
思想:剪枝 + 回溯(!!!!)
40. 组合综合Ⅱ(!!!)
思想: 回溯+剪枝
参考别人写的:
自己写的(超时):
具体分析:
41. 缺失的第一个正数
原地哈希(!!!)
42. 接雨水
思想:左右双指针,记录左右最大值
43. 字符串相乘
思想: 通过字典将字符串转为数字
46. 全排列
思想: 位标记+回溯算法
47.全排类Ⅱ
思想:位运算标记+回溯+列表去重
48. 旋转图像
53. 最大子数组和(很重要!!!)
思想: 动态规划,定义dp_i为以nums[i]结尾的最大连续子数组之和,然后进行状态转移
54. 螺旋矩阵(思想非常奇妙!)
思想: 定义上下左右边界,遍历后就重置边界!
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
if matrix == None:
return None
# 1. 定义上下左右边界
up = 0
down = len(matrix) - 1
left = 0
right = len(matrix[0]) - 1
res = []
while True:
# 2. 右行
for i in range(left, right+1):
res.append(matrix[up][i])
up += 1
if up > down:
break
# 3. 下行
for i in range(up, down+1):
res.append(matrix[i][right])
right -= 1
if right < left:
break
# 4. 左行
for i in range(right, left-1, -1):
res.append(matrix[down][i])
down -= 1
if down < up:
break
# 5. 上行
for i in range(down,up-1, -1):
res.append(matrix[i][left])
left += 1
if left > right:
break
return res
55. 跳跃游戏
思想: 标记起跳点能达到的最远距离,遍历;
59. 螺旋矩阵
思想:定义上下左右边界,然后循环遍历
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
if n < 1:
return None
# 1. 生成二维list
res = [[0 for _ in range(n)] for _ in range(n)]
# 2. 定义初始位置上下左右边界 和 数值
l, r, t, b = 0, n-1, 0, n-1
num, target = 1, n**2
# 3. 按照螺旋顺序进行填充数据
while num <= target:
# 右行
for i in range(l, r+1):
res[t][i] = num
num += 1
t += 1
# 下行
for j in range(t, b+1):
res[j][r] = num
num += 1
r -= 1
# 左行
for k in range(r, l-1, -1):
res[b][k] =num
num += 1
b -= 1
# 上行
for z in range(b, t-1, -1):
res[z][l] = num
num += 1
l += 1
return res
61. 旋转链表
思想:前后双指针,且间隔k个间距
# 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]:
# 1.判空
if head == None:
return None
# 2. 计算链表长度
pre = head
num = 1
while pre.next != None:
num += 1
pre = pre.next
k = k % num
if k == 0:
return head
pre = head
end = head
# 3.按end与pred间距k各单位
for i in range(k):
if end.next != None:
end = end.next
# 4. 间隔k使end至末尾点
while end.next != None:
end = end.next
pre = pre.next
# 5. 使末尾执行头节点
end.next = head
# 6. 令pred.next 为头节点,并返回
head = pre.next
pre.next = None
return head
62. 不同路径
思想:每一格的路径数 = 上面和左边的路径之和
73. 矩阵置零
思想1:先扫描一边,使用两个listt分别记录哪些行,哪些列有0;然后再遍历去置零
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
# 1. 判断空处理
if matrix == None:
return None
# 2.记录出现0的行列号
row = []
cul = []
for i in range(len(matrix)):
for j in range(len(matrix[0])):
if matrix[i][j] == 0:
if i not in row:
row.append(i)
if j not in cul:
cul.append(j)
# 3. 清零
# 3.1 行清0
for i in row:
for j in range(len(matrix[0])):
matrix[i][j] = 0
for j in cul:
for i in range(len(matrix)):
matrix[i][j] = 0
思想2***: 先使用两个标志位,记录第一行和第一列是否有0, 然后从第2行、第2列扫描,如果有0,则使用第一行和第一列对应位置记录;最后,根据扫描第一行和第一列的位置,置零。
借鉴的讨论区大佬的代码:
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
row = len(matrix)
col = len(matrix[0])
row0_flag = False
col0_flag = False
# 找第一行是否有0
for j in range(col):
if matrix[0][j] == 0:
row0_flag = True
break
# 第一列是否有0
for i in range(row):
if matrix[i][0] == 0:
col0_flag = True
break
# 把第一行或者第一列作为 标志位
for i in range(1, row):
for j in range(1, col):
if matrix[i][j] == 0:
matrix[i][0] = matrix[0][j] = 0
#print(matrix)
# 置0
for i in range(1, row):
for j in range(1, col):
if matrix[i][0] == 0 or matrix[0][j] == 0:
matrix[i][j] = 0
if row0_flag:
for j in range(col):
matrix[0][j] = 0
if col0_flag:
for i in range(row):
matrix[i][0] = 0
作者:powcai
链接:https://leetcode.cn/problems/set-matrix-zeroes/solutions/6594/o1kong-jian-by-powcai/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
102. 二叉树的层序遍历
思想:使用队列实现,在python中队列: queue = collections.deque([root]),即可完成初始化
77.组合(从[1, n]中选出所有k个数的组合)**
思路:排列组合的一个公式,C(n, k) = C(n - 1, k) + C(n - 1, k - 1)。从n个数中选k个数的所有情况可以分为“没选第n个数”和“选了第n个数”两类。如果没选第n个数,那么k个数全部从其余的n - 1个数中选出,共有C(n - 1, k)种方式;如果选了第n个数,那还需要从剩余的n - 1个数中选k - 1个数,共有C(n - 1, k - 1)种方式:
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
if k == 1:
return [[i] for i in range(1, n+1)]
if k == n:
return [list(range(1, n+1))]
return self.combine(n=n-1, k=k) + [ [n] + x for x in self.combine(n=n-1, k=k-1) ]
82. 删除有序链表中的重复元素
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head
# (重要)设置一个哑节点,防止头节点被删除,最后返回dummy即可
dummy = ListNode(0)
dummy.next = head
pre, cur = dummy, head
while cur:
# Step1: 重复节点的最后位置
while cur.next and cur.val == cur.next.val:
cur = cur.next
# 移动pre指针
if pre.next == cur:
pre = pre.next
else:
pre.next = cur.next
cur = cur.next
return dummy.next