283
class Solution(object):
def moveZeroes(self, nums):
i = 0
zero_num = 0
while i < len(nums):
if nums[i] == 0:
del nums[i]
zero_num += 1
else:
i += 1
return nums.extend([0]*zero_num)
练习:27 26 80
27. 移除元素
class Solution(object):
def removeElement(self, nums, val):
if not nums:
return 0
i = 0
while i < len(nums):
if nums[i] == val:
nums[i] = nums[-1] # 题目对顺序无要求 可以避免大量的元素移动
del nums[-1]
else:
i += 1
return len(nums)
75. 颜色分类
计数排序
class Solution(object):
def sortColors(self, nums):
zero, one, two = 0, 0, 0
for num in nums:
if num == 0:
zero += 1
if num == 1:
one += 1
if num == 2:
two += 1
for i in range(len(nums)):
if zero != 0:
nums[i] = 0
zero -= 1
elif one != 0:
nums[i] = 1
one -= 1
else:
nums[i] = 2
练习:88 215
167. 两数之和 II - 输入有序数组
因为有序所以可以尝试二分查找的思想
class Solution(object):
def twoSum(self, numbers, target):
if not numbers:
return
low = 0
high = len(numbers) - 1
while low < high:
if numbers[low] + numbers[high] == target:
return [low+1, high+1]
elif numbers[low] + numbers[high] > target:
high -= 1
else:
low += 1
return
练习:125 344 345 11
209
复杂度较高重新编写
class Solution(object):
def minSubArrayLen(self, s, nums):
if not nums:
return 0
if max(nums) >= s:
return 1
i, j = 0, 1
res = []
while j != len(nums):
if sum(nums[i:j+1]) >= s:
res.append(j+1 - i)
i += 1
else:
j += 1
if not res:
return 0
else:
return min(res)
3. 无重复字符的最长子串
class Solution(object):
def lengthOfLongestSubstring(self, s):
if not s:
return 0
left, right = 0, -1
res = 0
dic = dict()
while left < len(s): # 当还有子串时继续滑动
# 如果right还可以向右滑动并且滑动后的值不重复
if right+1 < len(s) and s[right+1] not in dic:
right += 1
dic[s[right]] = 1
res = max(res, right - left +1) #
else:
del dic[s[left]] # 如果重复逐个从left删除 直到不重复为止
left += 1
return res
练习:438 76
349. 两个数组的交集
class Solution(object):
def intersection(self, nums1, nums2):
if not nums1 or not nums2:
return []
return list(set(nums1) & set(nums2))
这两个时间复杂度和空间复杂度几乎相同
class Solution:
def intersection(self, nums1, nums2):
lst = []
a_set = set(nums1)
b_set = set(nums2)
for a in a_set:
if a in b_set:
lst.append(a)
return lst
350. 两个数组的交集 II
class Solution(object):
def intersect(self, nums1, nums2):
if not nums1 or not nums2:
return []
res = []
dic1 = dict()
dic2 = dict()
for num in nums1:
if num not in dic1:
dic1[num] = 1
else:
dic1[num] += 1
for num in nums2:
if num in dic1:
if num not in dic2:
dic2[num] = 1
else:
dic2[num] += 1
for num in dic2:
res.extend([num]*min(dic1[num], dic2[num]))
return res
练习:136 242 202 290 205 451
1. 两数之和
class Solution(object):
def twoSum(self, nums, target):
if not nums:
return []
dic = dict()
for i in range(len(nums)):
# 对于有重复值的特殊情况,若查找成功直接返回,查找失败对索引进行更新,不会影响后续查找
if target - nums[i] not in dic:
dic[nums[i]] = i
else:
return [i, dic[target - nums[i]]]
return []
练习:15 18 16
454. 四数相加 II
class Solution:
def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:
if not A or not B or not C or not D:
return 0
dic1 = dict()
res = 0
for i in A:
for j in B:
if i+j not in dic1:
dic1[i+j] = 1
else:
dic1[i+j] += 1
for i in C:
for j in D:
if -(i+j) in dic1:
# 对于cd中的1种情况 dic1中有dic1[-(i+j)]种情况与之对应
res += dic1[-(i+j)]
return res
练习:49
447. 回旋镖的数量
class Solution:
def distance(self, p1, p2):
# 注意 a**2 + b**2 比 a*a + b*b 耗时!
return (p1[0]-p2[0])*(p1[0]-p2[0]) + (p1[1]-p2[1])*(p1[1]-p2[1])
def numberOfBoomerangs(self, points: List[List[int]]) -> int:
if not points:
return 0
res = 0
for point in points:
dic = dict()
for tmp in points:
if point != tmp:
dist = self.distance(point, tmp)
if dist not in dic:
dic[dist] = 1
else:
dic[dist] += 1
for num in dic:
res += dic[num]*(dic[num]-1) # 等于1 也没有关系 1 *(1-1)= 0
return res
练习:149 719
219. 存在重复元素 II
# 滑动窗口+查找表
class Solution:
def containsNearbyDuplicate(self, nums, k):
if len(nums) <= 1:
return False
if k <= 0:
return False
record = set() # 初始化一个滑动窗口 每次都在该滑动窗口内进行寻找
for i in range(len(nums)):
if nums[i] in record:
return True
record.add(nums[i])
if len(record) == k+1: # 超过滑动窗口范围
record.remove(nums[i- k])
return False
class Solution(object):
def containsNearbyDuplicate(self, nums, k):
if not nums:
return False
dic = dict()
for i in range(len(nums)):
if nums[i] not in dic: # 第一次出现将元素设为key 索引设为value
dic[nums[i]] = i
elif abs(dic[nums[i]] - i) <= k: # 不是首次出现 判断是否满足条件
return True
else: # 不是首次出现 也不满足条件 则更新该key
dic[nums[i]] = i
return False
220. 存在重复元素 III
class Solution:
def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
if not nums or k <= 0 or t < 0 or k == 10000:
return False
record = dict() # 滑动窗口
for i in range(len(nums)):
if record: # 对滑动窗口的值进行判断,如果满足绝对值最大为t 则返回
for num in record:
if abs(nums[i] - record[num]) <= t:
return True
# 模拟滑动窗口的移动
record[i] = nums[i] # 不满足条件就后移一位放入滑动窗口
if len(record) == k+1: # 判断加入新的值后 滑动窗口的范围是否 超了
del record[i-k] # 如果超了 删除最后一位
return False
206. 反转链表
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre = None
cur = head
while cur:
tmp = cur.next
cur.next = pre
pre= cur
cur = tmp
return pre
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head):
if not head or not head.next:
return head
pHead = ListNode(0)
pHead.next = head
pre = head
cur = head.next
while cur:
pre.next = cur.next
cur.next = pHead.next
pHead.next = cur
cur = pre.next
return pHead.next
练习:92 83 86 328 2 445
203. 移除链表元素
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def removeElements(self, head, val):
pHead = ListNode(0)
pHead.next = head
left = pHead
right = pHead.next
while right:
if right.val == val:
left.next = right.next
right = left.next
else:
left = left.next
right = right.next
return pHead.next
练习:82 21
24. 两两交换链表中的节点
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
# 使用虚拟头结点
class Solution(object):
def swapPairs(self, head):
pHead = ListNode(0)
pHead.next = head
p = pHead
while p.next and p.next.next: # 保证要交换的两个节点存在
node1 = p.next
node2 = node1.next
node1.next = node2.next
node2.next = node1
p.next = node2
p = node1 # 对p进行更新 准备进入下一次循环
return pHead.next
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
# 递归法
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head # 递归退出条件
# 对两个节点进行交换
cur = head.next
head.next = cur.next
cur.next = head
# 对剩余节点进行递归交换
head.next = self.swapPairs(head.next)
return cur # 交换后第一个节点为cur
练习:25 147 148
237. 删除链表中的节点
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def deleteNode(self, node):
node.val = node.next.val # 用下一个节点的值将当前节点值覆盖
node.next = node.next.next # 用一个节点的指针将当前节点的指针覆盖
19. 删除链表的倒数第N个节点
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def removeNthFromEnd(self, head, n):
if not head:
return []
pHead = ListNode(0)
pHead.next = head
pre = pHead
left = pHead.next
right = pHead.next
for _ in range(n):
right = right.next
while right:
right = right.next
left = left.next
pre = pre.next
pre.next = left.next
return pHead.next
练习:61 143 234
20. 有效的括号
class Solution:
def isValid(self, s: str) -> bool:
dic = {'(':')', '[':']','{':'}'}
stack = []
for char in s:
if char in dic:
stack.append(char)
elif not stack or dic[stack.pop()] != char:
return False
return len(stack) == 0
class Solution:
def isValid(self, s: str) -> bool:
if not s:
return True
if len(s) % 2 != 0:
return False
dic = {'(':')', '[':']','{':'}'}
stack = []
for char in s:
if char in dic:
stack.append(char)
elif stack:
tmp = stack.pop()
if dic[tmp] == char:
continue
else:
return False
else:
return False
return len(stack) == 0
练习:150 71
144. 二叉树的前序遍历
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
# 非递归实现
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack = [root]
result = []
while stack:
node = stack.pop()
result.append(node.val)
# 因为要先遍历左子树 所以要先将右子树入栈 先进后出!
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return result
94. 二叉树的中序遍历
class Solution:
def __init__(self):
self.res = []
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack = []
while stack or root:
while root:
stack.append(root)
root = root.left
root = stack.pop()
self.res.append(root.val)
root = root.right
return self.res
145. 二叉树的后序遍历
class Solution:
def __init__(self):
self.res = []
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack1 = [root]
stack2 = []
while stack1:
node = stack1.pop()
stack2.append(node.val)
if node.left:
stack1.append(node.left)
if node.right:
stack1.append(node.right)
while stack2:
self.res.append(stack2.pop())
return self.res
练习:341
102. 二叉树的层次遍历
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
queue = [root]
res = []
while queue:
k = len(queue)
tmp = []
for _ in range(k):
node = queue.pop(0)
tmp.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
res.append(tmp)
return res
练习:107 103 199 346
279
练习:127 126 286
347
练习:23
104. 二叉树的最大深度
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root):
if not root:
return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right))+1
111. 二叉树的最小深度
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
# 路径的最后一个节点必须是叶子节点
class Solution:
def minDepth(self, root: TreeNode) -> int:
if not root:
return 0
if not root.left: # 对根节点没有左子树的情况进行判断
return self.minDepth(root.right) + 1
if not root.right: # 对根节点没有右子树的情况进行判断
return self.minDepth(root.left) + 1
return min(self.minDepth(root.left), self.minDepth(root.right)) + 1 # 根节点同时有左右子树
226. 翻转二叉树
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return
self.invertTree(root.left)
self.invertTree(root.right)
tmp = root.left
root.left = root.right
root.right = tmp
return root
练习:100 101 222 110
112. 路径总和
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if not root: # 当前节点为空,则退出递归
return False
if not root.left and not root.right: # 当前结点不为空,且为叶子节点
return sum == root.val # 判断叶子节点是否等于剩余数字
return self.hasPathSum(root.left, sum - root.val) or \
self.hasPathSum(root.right, sum - root.val)
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.sum = 0
self.res = []
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if not root:
return False
self.sum += root.val
if not root.left and not root.right and self.sum == sum:
self.res.append(1) # 如果有满足条件的路径则添加一个记录
self.hasPathSum(root.left, sum)
self.hasPathSum(root.right, sum)
self.sum -= root.val # 如果不满足条件则减去改值
return len(self.res) != 0
练习:111 404
257. 二叉树的所有路径
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def find_paths(self, root, res, path):
if not root: # 递归出口
return
path += str(root.val)
if not root.left and not root.right: # 当前节点是叶子节点
res.append(path) # 把路径加入到答案中
return
path += '->' # 当前节点不是叶子节点,继续递归遍历
self.find_paths(root.left, res, path)
self.find_paths(root.right, res, path)
def binaryTreePaths(self, root: TreeNode) -> List[str]:
res = []
path = ''
self.find_paths(root, res, path)
return res
练习:113 129 222
113. 路径总和 II
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.path = []
self.res = []
self.sum = 0
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
if not root:
return
self.sum += root.val
self.path.append(root.val)
if not root.left and not root.right and self.sum == sum:
self.res.append(self.path[:])
self.pathSum(root.left, sum)
self.pathSum(root.right, sum)
self.sum -= root.val
self.path.pop()
return self.res
437. 路径总和 III
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def findPath(self, root, num):
if not root:
return 0
count = 0 # 每进入一次递归就要记录可能满足条件的路径个数
if root.val == num:
count += 1 # 如果当前结点值满足条件
# 如满足if条件,判断子树之和是否有0的情况;若不满足if,判断是否子树之和 加 root.val等于num
count += self.findPath(root.left, num - root.val)
count += self.findPath(root.right, num - root.val)
return count
def pathSum(self, root: TreeNode, sum: int) -> int:
if not root:
return 0
# 和为sum 共有两种情况 包含跟结点与不包含根节点
return self.findPath(root, sum) + self.pathSum(root.left, sum) \
+ self.pathSum(root.right, sum) # 注意此时不是sum - root.val
783. 二叉搜索树结点最小距离
'''
直观的思路是先将二叉树进行中序遍历并将结果放入数组中,然后对数组进行遍历,时间空间复杂度均为O(n)。
其实可以不用存储中序遍历的结果,而是用一个变量pre来储存中序遍历上一个节点的值,空间复杂度降低到O(1)。
'''
class Solution:
def in_order(self, node):
if not node:
return
self.in_order(node.left)
self.res = min(self.res, node.val - self.pre)
self.pre = node.val
self.in_order(node.right)
def minDiffInBST(self, root: TreeNode) -> int:
self.pre = float('-inf')
self.res = float('inf')
self.in_order(root)
return self.res
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def minDiffInBST(self, root: TreeNode) -> int:
if not root:
return
nums = []
def in_order(root):
if not root:
return
in_order(root.left)
nums.append(root.val)
in_order(root.right)
in_order(root)
n = len(nums)
minNum = float('inf')
for i in range(n-1):
minNum = min(minNum, nums[i+1]-nums[i])
return minNum
235. 二叉搜索树的最近公共祖先
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
# 共有五种情况 pq同在根节点两侧 pq分别在根节点两侧 或pq其中有一个为祖先
class Solution:
def lowestCommonAncestor(self, root, p, q):
if not root:
return
if p.val < root.val and q.val < root.val: # pq同在根节点左侧 公共祖先肯定在左子树上
return self.lowestCommonAncestor(root.left, p, q) # 在左子树上寻找
if p.val > root.val and q.val > root.val: # pq同在根节点右侧 公共祖先肯定在右子树上
return self.lowestCommonAncestor(root.right, p, q)# 在右子树上寻找
return root # 其他三种情况 当前结点即为最近公共祖先
练习:98 450 108 230 236 530
17. 电话号码的字母组合
class Solution:
def letterCombinations(self, digits):
lookup = {
'2':['a','b','c'], '3':['d','e','f'], '4':['g','h','i'], '5':['j','k','l'],
'6':['m','n','o'], '7':['p','q','r','s'], '8':['t','u','v'], '9':['w','x','y','z']
}
def helper(digits, s):
if not digits:
res.append(s)
return
cur_digit = digits[0] # 第一个即为当前要遍历的数字
# 将当前数字代表的字母依次加入到s中, 然后再对下一个数字进行处理
for char in lookup[cur_digit]: # 取出当前数字对应的字符 并对其进行遍历
helper(digits[1:], s+char)
if not digits:
return []
res = []
helper(digits, '')
return res
练习:93 131
46. 全排列
class Solution:
def permute(self, nums):
if not nums:
return []
n = len(nums)
if n == 1:
return [nums]
res = []
for i in range(n): # 逐渐缩小问题规模
tmp = self.permute(nums[:i]+nums[i+1:])
for j in tmp:
res.append([nums[i]]+j)
return res
class Solution:
def permute(self, nums):
def helper(nums, index, p):
if index == len(nums): # 当达到指定个数时
res.append(p[:])
return
for i in range(len(nums)): # 对每一个数字进行遍历
if not used[i]: # 如果当前数字并未被使用
used[i] = 1 # 标记已经使用
p.append(nums[i]) # 使用
helper(nums, index + 1, p) # 对剩余数字进行判断
p.pop() # 使用完成后要对当前数字进行释放 并将标记置为未使用
used[i] = 0 # 状态回溯
if not nums:
return []
res = []
used = [0 for i in range(len(nums))] # 用于记录当前索引的数字是否已经使用
helper(nums, 0, []) # 传入要全排列的列表,起始位置,暂存全排列的列表
return res
练习:47
77. 组合
class Solution:
def combine(self, n, k):
def helper(start, p): # 从当前索引往后的范围内取数并加入到p中
if len(p) == k: # 如果已经达到个数 则将其加入到结果列表中
res.append(p[:])
return
# [i...n] 中至少要有k-len(cur)个元素i最多为n-(k-len(cur))+1
for i in range(start, n-(k-len(cur))+ 2): # 剪枝操作
p.append(i) # 当前数字
helper(i+1, p) # 将当前数字排除 并递归地从中取数
p.pop() # 将p加入res中后 要逐层将其释放
if n < 1 or k < 1 or k > n:
return []
res = []
helper(1, [])
return res
练习:39 40 216 78 90 401
79
class Solution:
def exist(self, board, word):
if not board:
return False
m = len(board) # 行数
n = len(board[0]) # 列数
directions = [(0, -1), (-1, 0), (0, 1), (1, 0)]
visited = [[False for _ in range(n)] for _ in range(m)] # 用于记录的矩阵
def searchWord(index, i, j):
if index == len(word) - 1: # 递归终止条件
return board[i][j] == word[index] # 判断最后一个元素与矩阵中元素是否相等
if board[i][j] == word[index]: # 当前元素匹配之后 再去匹配下一个
visited[i][j] = True # 对标记进行更新
for d in directions:
new_i = i + d[0]
new_j = j + d[1]
# 确保更新之后的xy在矩阵范围内,并且该元素并未被使用过
if 0 <= new_i < m and 0 <= new_j < n and not visited[new_i][new_j] and \
searchWord(index + 1, new_i, new_j):
return True # 注意:如果这一次 search word 成功的话,就返回
visited[i][j] = False # 将对应位置做出标记
return False
for i in range(m):
for j in range(n): # 遍历每一个元素
if searchWord(0, i, j):
return True # 找到返回 True
return False # 没有找到 False
200. 岛屿数量
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
m = len(grid)
if m == 0:
return 0
n = len(grid[0])
res = 0
directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]
visited = [[False for _ in range(n)] for _ in range(m)]
def dfs(i,j):
visited[i][j] = True
for d in directions:
new_i = i + d[0]
new_j = j + d[1]
if 0 <= new_i < m and 0 <= new_j < n and not visited[new_i][new_j] and grid[new_i][new_j] == '1':
dfs(new_i, new_j)
for i in range(m):
for j in range(n):
if not visited[i][j] and grid[i][j] == '1':
res += 1
dfs(i, j)
return res
练习:130 417
51
练习:52 37
70. 爬楼梯
class Solution:
def climbStairs(self, n):
if n <= 3:
return n
res = [2, 3]
for _ in range(n-3):
res.append(res[-1] + res[-2])
return res[-1]
练习:120 64
343
练习:279 91 62 63
198
练习:213 337 309
416
练习:322 377 474 139 494
300
练习:376
455
练习:392
435
62. 不同路径
思路一:动态规划
# 时间复杂度:O(m*n)
# 空间复杂度:O(m*n)
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [[1 for _ in range(n)] for _ in range(m)] #第一行或者第一列都是在边界,只能为 1
for i in range(1, m):
for j in range(1, n):
dp[i][j] = dp[i-1][j] + dp[i][j-1] #dp[i][j]是到达i,j最多路径,dp[i][j]=dp[i-1][j]+dp[i][j-1]
return dp[-1][-1]
优化:
class Solution:
# 因为每次只需要 dp[i-1][j],dp[i][j-1] 所以我们只要记录这两个数
def uniquePaths(self, m: int, n: int) -> int:
dp = [1]*n
for i in range(1, m):
for j in range(1, n):
dp[j] += dp[j-1]
return dp[-1]
思路二:排列组合
机器人一定会走m+n-2步,即从m+n-2中挑出m-1步向下走就行了,即。
63. 不同路径 II
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid):
if not obstacleGrid or not obstacleGrid[0]:
return 0
m, n = len(obstacleGrid), len(obstacleGrid[0])
dp = [1] + [0]*n # 先假设有一条路径
for i in range(m): # 走每一个网格
for j in range(n):
if obstacleGrid[i][j]: # 如果存在障碍物
dp[j] = 0 # 当前路径不可通过
else: # 如果不存在障碍物
dp[j] = dp[j]+dp[j-1] # 当前路径加上另一个方向的路径和
return dp[-2]
64. 最小路径和
class Solution:
def minPathSum(self, grid):
if not grid or not grid[0]:
return 0
m, n = len(grid), len(grid[0])
dp = [0]*n
dp[0] = grid[0][0]
for i in range(1,n):
dp[i] = dp[i-1] + grid[0][i]
for i in range(1,m):
dp[0] = grid[i][0] + dp[0]
for j in range(1,n):
dp[j]= min(dp[j],dp[j-1]) + grid[i][j]
return dp[-1]
153. 寻找旋转排序数组中的最小值
1 two sum
对于stack和queue,除了pop外,查找的时间复杂度是O(n)。hash map, 查找的时间复杂度理想情况下是O(1)。所以先来考虑
hash map来求解这个问题。python中的字典dictionary在查找key时使用的是hashmap的方式,查找速度较快
class Solution(object):
def twoSum(self, nums, target):
lookup = {} # 定义新的缓冲区,可以得到“空间换时间”的效果,降低时间复杂度
for i, num in enumerate(nums): # 遍历一次,时间复杂度O(n)
if target - num in lookup: # hashmap查找,时间复杂度O(1)
return [lookup[target - num], i] # 若查找成功直接返回索引
else:
lookup[num] = i # 查找失败,以数字为键索引为值添加的字典中
7 Reverse Integer
Python采用切片实现逆序非常简单,但是切片的对象可以是字符串、列表、元组,没有整数。
因此要对整数实现逆序,首先就要把整数变成字符串,逆序后再由字符串变成整数。
class Solution(object):
def reverse(self, x):
if x < 0: # 处理负数时,现将负数变成正数,逆序后再乘以负一
y = -1 * int(str(-x)[::-1])
else:
y = int(str(x)[::-1])
return y if -2**-31 <= y <= 2**31-1 else 0
9 Palindrome Number
class Solution:
def isPalindrome(self, x):
if x < 0:
return False
elif x != int(str(x)[::-1])
return False
else:
return True
21. 合并两个有序链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
p1, p2 = l1, l2
head = ListNode(0)
cur = head
while p1 and p2:
if p1.val <= p2.val:
cur.next = p1
cur = cur.next
p1 = p1.next
else:
cur.next = p2
cur = cur.next
p2 = p2.next
if p1:
cur.next = p1
if p2:
cur.next = p2
return head.next
23. 合并K个排序链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
# 与归并排序思路一样,先对n个待排序的链表进行拆分,然后再两两进行排序
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
def merge(list1, list2):
head = ListNode(0)
cur = head
while list1 and list2:
if list1.val < list2.val:
cur.next = list1
list1 = list1.next
cur = cur.next
else:
cur.next = list2
list2 = list2.next
cur = cur.next
if list1:
cur.next = list1
if list2:
cur.next = list2
return head.next
if not lists:
return
n = len(lists)
if n == 1:
return lists[0]
mid = n//2
list1 = self.mergeKLists(lists[:mid])
list2 = self.mergeKLists(lists[mid:])
return merge(list1, list2)
98. 验证二叉搜索树
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def isValidBST(self, root):
def inOrder(root):
if not root:
return
inOrder(root.left)
res.append(root.val)
inOrder(root.right)
res = []
inOrder(root)
for i in range(len(res)-1):
if res[i] >= res[i+1]:
return False
return True
101. 对称二叉树
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def is_mirror(self, left, right):
if not left and not right:
return True
if not left or not right:
return False
if left.val == right.val:
return self.is_mirror(left.left, right.right) and self.is_mirror(left.right, right.left)
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
return self.is_mirror(root.left, root.right)
103. 二叉树的锯齿形层次遍历
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
queue = [root]
res = []
k = 0
while queue:
n = len(queue)
tmp = []
k += 1
for _ in range(n):
node = queue.pop(0)
tmp.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
if k % 2 == 1:
res.append(tmp)
else:
res.append(tmp[::-1])
return res
108. 将有序数组转换为二叉搜索树
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
if not nums:
return
mid = len(nums) // 2
node = TreeNode(nums[mid])
node.left = self.sortedArrayToBST(nums[:mid])
node.right = self.sortedArrayToBST(nums[mid+1:])
return node
110. 平衡二叉树
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def get_depth(self, root): # 从下往上遍历,减少每个结点需要遍历的次数
if not root:
return 0
left = self.get_depth(root.left) # 要么返回-1表示不是平衡二叉树,要么返回树的深度
if left == -1: # 若左子树不是平衡二叉树
return -1
right = self.get_depth(root.right)
if right == -1: # 若右子树不是平衡二叉树
return -1
if abs(left - right) > 1: # 从下往上判断当前子树是否为平衡二叉树
return -1 # 若不是 直接返回-1
return max(left, right) + 1 # 若是平衡二叉树 返回当前子树的深度
def isBalanced(self, root: TreeNode) -> bool:
return self.get_depth(root) != -1
138. 复制带随机指针的链表
"""
# Definition for a Node.
class Node:
def __init__(self, val, next, random):
self.val = val
self.next = next
self.random = random
"""
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if not head:
return
# 第一步:复制链表
cur = head
while cur:
node = Node(cur.val, None, None)
node.next = cur.next
cur.next = node
cur = node.next
# 第二步:复制随机指针
cur = head
while cur:
if cur.random:
cur.next.random = cur.random.next
cur = cur.next.next
# 第三步:链表拆分
cur = head
pHead = head.next
pCur = pHead
while cur:
cur.next = cur.next.next
if pCur.next:
pCur.next = pCur.next.next
cur = cur.next
pCur = pCur.next
return pHead
141. 环形链表
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def hasCycle(self, head):
if not head:
return False
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
142. 环形链表 II
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
def find_loop(head):
if not head:
return
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return slow
return
end = find_loop(head)
if not head or not end:
return
begin = head
while begin != end:
begin = begin.next
end = end.next
return end
155. 最小栈
class MinStack(object):
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, x):
self.stack1.append(x)
if not self.stack2 or x <= self.stack2[-1]:
self.stack2.append(x)
def pop(self):
if self.stack1[-1] == self.stack2[-1]:
self.stack2.pop()
self.stack1.pop()
def top(self):
return self.stack1[-1]
def getMin(self):
if self.stack2:
return self.stack2[-1]
return
160. 相交链表
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
if not headA or not headB:
return
p, q = headA, headB
len1, len2 = 0, 0
while p:
len1 += 1
p = p.next
while q:
len2 += 1
q = q.next
if len1 > len2:
p, q = headA, headB
else:
p, q = headB, headA
for _ in range(abs(len1 - len2)):
p = p.next
while p != q:
p = p.next
q = q.next
return p
215. 数组中的第K个最大元素
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
def adjust_heap(nums, i, n):
left = 2*i + 1
right = 2*i + 2
maxS = i
if i <= n//2:
if left < n and nums[left] > nums[maxS]:
maxS = left
if right < n and nums[right] > nums[maxS]:
maxS = right
if maxS != i:
nums[i], nums[maxS] = nums[maxS], nums[i]
adjust_heap(nums, maxS, n)
def build_heap(nums, n):
for i in range(n//2)[::-1]:
adjust_heap(nums, i, n)
n = len(nums)
build_heap(nums, n)
for i in range(n)[::-1]: # 逐个将堆顶元素放到有序数组中
nums[0], nums[i] = nums[i], nums[0]
adjust_heap(nums, 0, i)
print(nums)
return nums[-k]
230. 二叉搜索树中第K小的元素
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.m = 0
self.res = []
def kthSmallest(self, root: TreeNode, k: int) -> int:
if not root:
return
self.kthSmallest(root.left, k)
self.m += 1
if self.m == k:
self.res.append(root.val)
self.kthSmallest(root.right, k)
if self.res:
return self.res[0]
263. 丑数
class Solution:
def isUgly(self, num: int) -> bool:
if num <= 0:
return False
if num == 1:
return True
while num > 1:
if num % 2 == 0: # 除2余0 即能被2整除
num /= 2
elif num % 3 == 0: # 能被3整除
num /= 3
elif num % 5 == 0: # 能被5整除
num /= 5
else:
return False # 不能被235整除则不是丑数
return True # num最后为1时 该数为丑数
264. 丑数 II
class Solution:
def nthUglyNumber(self, n: int) -> int:
if n <= 1:
return n
res = [1] * n
i2, i3, i5 = 0, 0, 0 # 所有丑数肯定是之前的数字乘 235 得到的
for i in range(1, n):
num2 = res[i2] * 2 # 模拟之前丑数乘2得到的队列
num3 = res[i3] * 3 # 模拟乘3得到的队列
num5 = res[i5] * 5 # 模拟乘5得到的队列
res[i] = min(num2,min(num3, num5)) # 在三个队列中取出一个最小的放入当前位置
if res[i] == num2:
i2 += 1 # 模拟出队
if res[i] == num3:
i3 += 1
if res[i] == num5:
i5 += 1
return res[-1]
347. 前 K 个高频元素
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
if not nums or k < 1:
return []
dic = dict()
res = []
for num in nums:
if num not in dic:
dic[num] = 1
else:
dic[num] += 1
items = list(dic.items())
items.sort(key = lambda x: -x[1])
res = [tmp[0] for tmp in items]
return res[:k]
449. 序列化和反序列化二叉搜索树
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Codec:
def serialize(self, root):
def pre_order(root):
if not root:
res.append("#")
return
res.append(str(root.val))
pre_order(root.left)
pre_order(root.right)
res = []
pre_order(root)
return ' '.join(res)
def deserialize(self, data):
nums = iter(data.split())
def pre_order():
num = next(nums)
if num =="#":
return
node = TreeNode(int(num))
node.left = pre_order()
node.right = pre_order()
return node
return pre_order()
572. 另一个树的子树
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSub(self, a, b):
if a == b:
return True
if a and b and a.val == b.val:
return self.isSub(a.left, b.left) and self.isSub(a.right, b.right)
else:
return False
def isSubtree(self, s: TreeNode, t: TreeNode) -> bool:
if not s or not t:
return False
return self.isSub(s, t) or self.isSubtree(s.left, t) or self.isSubtree(s.right, t)
704. 二分查找
class Solution:
def search(self, nums: List[int], target: int) -> int:
if not nums:
return -1
n = len(nums)
left = 0
right = n-1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
elif nums[mid] > target:
right = mid-1
else:
left = mid + 1
return -1
852. 山脉数组的峰顶索引
class Solution:
def peakIndexInMountainArray(self, A: List[int]) -> int:
if not A:
return
n = len(A)
left = 0
right = n - 1
while left <= right:
mid = (left + right)//2
if A[mid] > A[mid+1] and A[mid] > A[mid-1]:
return mid
elif A[mid] > A[mid+1]:
right = mid
else:
left = mid