1. Two Sum
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
di = dict()
for i, elem in enumerate(nums):
if (target - elem) in di:
return [i, di[target-elem]]
di[elem] = i
字典(哈希表)解决法,开始犯了2个问题,一个是直接把所有值先存入字典,这样会导致可能找到2个同一元素;一个问题是返回时用di[elem],因为此时elem还没存入di。
2. Add Two Numbers
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
res = ListNode()
head = res
forward = 0
while l1 or l2:
v1 = l1.val if l1 is not None else 0
v2 = l2.val if l2 is not None else 0
tmp_val = v1 + v2 + forward
if tmp_val >= 10:
tmp_val = tmp_val - 10
forward = 1
else:
forward = 0
res.val = tmp_val
l1 = l1.next if l1 is not None else l1
l2 = l2.next if l2 is not None else l2
if l1 or l2:
res.next = ListNode()
res = res.next
if forward != 0:
res.next = ListNode()
res = res.next
res.val = forward
return head
写的过程出现的问题:1.没有设置head导致最后结果返回最后一位 2.每次循环开辟一个新的Node默认为0,导致最后会多出一个0,这个加一个判断是否到末尾 3.当l1和l2都走完后有可能还会有一次进位在最后需要判断
4.不够简洁,重新写。
3. Longest Substring Without Repeating Characters
先暴力解法
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
max_len = 0
for i in range(len(s)):
set_s = set()
current_len = 0
for j in range(i, len(s)):
if s[j] in set_s:
break
set_s.add(s[j])
current_len += 1
if current_len > max_len:
max_len = current_len
return max_len
滑动窗口解法,右边移动,如果碰到前面出现过的,左边移动至不重复再继续找。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
max_len = 0
current_len = 0
start = 0
set_s = set()
for end in range(len(s)):
current_len += 1
while s[end] in set_s:
current_len -= 1
set_s.remove(s[start])
start += 1
max_len = current_len if current_len > max_len else max_len
set_s.add(s[end])
return max_len
4. Median of Two Sorted Arrays
5. Longest Palindromic Substring
class Solution:
def longestPalindrome(self, s: str) -> str:
dp = [[False for i in range(len(s))] for j in range(len(s))]
for i in range(len(s)):
dp[i][i] = True
for i in range(len(s) - 1):
dp[i][i + 1] = True if s[i] == s[i + 1] else False
for i in range(len(s)):
for step in range(1, len(s)):
if i-step < 0 or i + step >= len(s) or not dp[i - step + 1][i + step - 1]:
break
dp[i - step][i + step] = True if s[i - step] == s[i + step] else False
for step in range(1, len(s) - 1):
if i - step < 0 or i + 1 + step >= len(s) or not dp[i - step + 1][i + step]:
break
dp[i - step][i + 1 + step] = True if s[i - step] == s[i + 1 + step] else False
max_str = ""
for i in range(len(s)):
for j in range(i, len(s)):
if dp[i][j] and j - i + 1 > len(max_str):
max_str = s[i:j + 1]
return max_str
10. Regular Expression Matching
11. Container With Most Water
class Solution:
def calcaute_area(self, height, left, right):
return min(height[left], height[right]) * (right - left)
def maxArea(self, height: List[int]) -> int:
left = 0
right = len(height) - 1
best_left = height[left]
best_right = height[right]
max_area = self.calcaute_area(height, left, right)
while left < right:
if height[left] < height[right]:
while height[left] <= best_left and left < right:
left += 1
else:
while height[right] <= best_right and left < right:
right -= 1
if left < right:
area = self.calcaute_area(height, left, right)
if area > max_area:
max_area = area
best_left = height[left]
best_right = height[right]
else:
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_area
双指针,关键在于指针移动顺序,因为面积取决于短板,所以率先移动短板指针。另外,相对简洁的官方答案,多加了一步:如果移动后的高度<=原来最优的高度,面积必然不会更大,所以可以跳过此种情况的计算。
15. 3Sum
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
arr = sorted(nums)
res = []
for i in range(len(arr)):
if arr[i] > 0:
break
if i > 0 and arr[i] == arr[i - 1]:
continue
left = i + 1
right = len(arr) - 1
while left < right:
if left > i + 1 and arr[left] == arr[left - 1] and left < right:
left += 1
continue
sum = arr[left] + arr[right] + arr[i]
if sum == 0:
res.append([arr[i], arr[left], arr[right]])
left += 1
right -= 1
elif sum > 0:
right -= 1
else:
left += 1
return res
三个数相加,先排序,遍历第一个数,然后后两个数用双指针。容易错的是结果不能重复,所以要限制第一第二个数不能重复(因为排序了所以判断和前一个数不同即可)
17. Letter Combinations of a Phone Number
19. Remove Nth Node From End of List
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
nums = 0
p = head
while p:
nums += 1
p = p.next
k = nums - n
pre = head
if k == 0:
head = head.next
return head
for i in range(k-1):
pre = pre.next
middle = pre.next
pro = middle.next
pre.next = pro
middle.next = None
return head
20. Valid Parentheses
class Solution:
def isValid(self, s: str) -> bool:
stack = []
valid_ch = {"[":"]", "{":"}", "(":")"}
for elem in s:
if len(stack) != 0 and valid_ch.get(stack[-1], None) == elem:
stack.pop()
else:
stack.append(elem)
return len(stack) == 0
21. Merge Two Sorted Lists
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
dummy_node = ListNode()
p = dummy_node
while list1 and list2:
if list1.val <= list2.val:
p.next = list1
list1 = list1.next
else:
p.next = list2
list2 = list2.next
p = p.next
p.next = list1 if list1 else list2
return dummy_node.next
22. Generate Parentheses
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
res = []
def dfs(s, left, right):
if left == 0 and right == 0:
res.append(s)
if left > right:
return
if left > 0:
dfs(s + "(", left - 1, right)
if right > 0:
dfs(s + ")", left, right - 1)
dfs("", n, n)
return res
31. Next Permutation
33. Search in Rotated Sorted Array
class Solution:
def search(self, nums: List[int], target: int) -> int:
low = 0
high = len(nums) - 1
while low <= high:
mid = int((low + high) / 2)
if nums[mid] == target:
return mid
if nums[low] <= nums[mid]:
if target < nums[mid] and target >= nums[low]:
high = mid - 1
else:
low = mid + 1
else:
if target > nums[mid] and target <= nums[high]:
low = mid + 1
else:
high = mid - 1
return -1
思路是二分查找,且左边或者右边至少有一个有序数组,找到有序数组,就可以直接判断target是否在其中。判断有序数组时,得用<=,等号涵盖了没有数的情况。
34. Find First and Last Position of Element in Sorted Array
39. Combination Sum
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
def dfs(candidates, target, cur_sum, arr, from_index):
if cur_sum == target:
res.append(arr.copy())
elif cur_sum > target:
return
for i in range(from_index, len(candidates)):
arr.append(candidates[i])
dfs(candidates, target, cur_sum + candidates[i], arr, i)
arr.pop()
dfs(candidates, target, 0, [], 0)
return res
注意数组加进去时要copy否则会在其他地方被改掉,再就是要加一个from_index,不再往回挑选导致重复。
46. Permutations
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
def dfs(nums, used_index, one):
if len(used_index) == len(nums):
res.append(one.copy())
for i in range(len(nums)):
if i in used_index:
continue
one.append(nums[i])
used_index.add(i)
dfs(nums, used_index, one)
one.pop()
used_index.discard(i)
dfs(nums, set(), [])
return res
48. Rotate Image
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
# f(i, j) => f(j, n-i-1)
# f(j, n-i-1) => f(n-i-1, n-j-1)
# f(n-i-1, n-j-1) => f(n-j-1, i)
# f(n-j-1, i) => f(i, j)
n = len(matrix)
visited = [[False for i in range(n)] for j in range(n)]
for i in range(n):
for j in range(n):
if not visited[i][j]:
visited[i][j] = True
visited[j][n-i-1] = True
visited[n-i-1][n-j-1] = True
visited[n-j-1][i] = True
t1 = matrix[i][j]
t2 = matrix[j][n-i-1]
t3 = matrix[n-i-1][n-j-1]
t4 = matrix[n-j-1][i]
matrix[j][n-i-1] = t1
matrix[n-i-1][n-j-1] = t2
matrix[n-j-1][i] = t3
matrix[i][j] = t4
49. Group Anagrams
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
di = dict()
for i, s in enumerate(strs):
new_s = "".join(sorted(s))
if new_s not in di:
di[new_s] = []
di[new_s].append(s)
return [elem for elem in di.values()]
53. Maximum Subarray
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
current_max = nums[0]
res = nums[0]
for i in range(1, len(nums)):
current_max = max(nums[i], current_max + nums[i])
if current_max > res:
res = current_max
return res
f(i)为0-i之间以i为结尾的最大sum,f(i) = max(f(i - 1) + nums[i], nums[i]),每进一位,看前面的串是否需要断掉。
55. Jump Game
class Solution:
def canJump(self, nums: List[int]) -> bool:
max_index = 0
for i, num in enumerate(nums[:-1]):
max_index = (num + i) if (num + i > max_index) else max_index
if max_index == i:
return False
if max_index >= len(nums) - 1:
return True
return False
每个位置判断目前能到达最远的地方,如果当前最远的地方就是当前位置,说明无法跳出。倒数第二位位置能到达最远地方如果>=最后一位,说明能到达,否则不能到达。
56. Merge Intervals
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
sorted_intervals = sorted(intervals, key=lambda x: x[0])
res = []
i = 0
while i < len(sorted_intervals):
current_left = sorted_intervals[i][0]
current_right = sorted_intervals[i][1]
while i < len(sorted_intervals) - 1 and current_right >= sorted_intervals[i+1][0]:
current_right = max(current_right, sorted_intervals[i+1][1])
i += 1
res.append([current_left, current_right])
i += 1
return res
62. Unique Paths
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
#count[mm][nn] = count[mm-1][nn] + count[mm][nn-1]
count = [[0] * n] * m
for mm in range(m):
count[mm][0] = 1
for nn in range(n):
count[0][nn] = 1
for mm in range(1, m):
for nn in range(1, n):
count[mm][nn] = count[mm-1][nn] + count[mm][nn-1]
return count[m-1][n-1]
64. Minimum Path Sum
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
m = len(grid)
n = len(grid[0])
res = [[0 for i in range(n)] for j in range(m)]
res[0][0] = grid[0][0]
for i in range(1, m):
res[i][0] = res[i-1][0] + grid[i][0]
for i in range(1, n):
res[0][i] = res[0][i-1] + grid[0][i]
for i in range(1, m):
for j in range(1, n):
res[i][j] = min(res[i-1][j], res[i][j-1]) + grid[i][j]
return res[m-1][n-1]
70. Climbing Stairs
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1:
return 1
if n == 2:
return 2
res = [0 for i in range(n)]
res[0] = 1
res[1] = 2
for i in range(2, n):
res[i] = res[i - 1] + res[i - 2]
return res[n - 1]
75. Sort Colors
class Solution:
def sortColors(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
count = [0, 0, 0]
for num in nums:
count[num] += 1
for i in range(len(nums)):
if i < count[0]:
nums[i] = 0
elif i < count[0] + count[1]:
nums[i] = 1
else:
nums[i] = 2
78. Subsets
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = []
def get_subset(nums, i, current):
if i == len(nums):
res.append(current)
return
get_subset(nums, i + 1, current.copy())
current.append(nums[i])
get_subset(nums, i + 1, current.copy())
get_subset(nums, 0, [])
return res
79. Word Search
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
board_row = len(board)
board_col = len(board[0])
def search_exist(board, word, index, used, i, j):
if index == len(word):
return True
up = (i - 1 >= 0) and (board[i - 1][j] == word[index]) and ((i - 1, j) not in used)
down = (i + 1 < board_row) and (board[i + 1][j] == word[index]) and ((i + 1, j) not in used)
left = (j - 1 >= 0) and (board[i][j - 1] == word[index]) and ((i, j - 1) not in used)
right = (j + 1 < board_col) and (board[i][j + 1] == word[index]) and ((i, j + 1) not in used)
if not (up or down or left or right):
return False
if up:
used.add((i - 1, j))
up = search_exist(board, word, index + 1, used, i - 1, j)
used.remove((i - 1, j))
if down:
used.add((i + 1, j))
down = search_exist(board, word, index + 1, used, i + 1, j)
used.remove((i + 1, j))
if left:
used.add((i, j - 1))
left = search_exist(board, word, index + 1, used, i, j - 1)
used.remove((i, j - 1))
if right:
used.add((i, j + 1))
right = search_exist(board, word, index + 1, used, i, j + 1)
used.remove((i, j + 1))
return up or down or left or right
for i in range(board_row):
for j in range(board_col):
if board[i][j] == word[0] and search_exist(board, word, 1, {(i, j)}, i, j):
return True
return False
96. Unique Binary Search Trees
class Solution:
def numTrees(self, n: int) -> int:
res = [0 for i in range(n + 1)]
res[0], res[1] = 1, 1
for i in range(2, n + 1):
tmp_res = 0
for j in range(0, i):
tmp_res += res[j] * res[i - j - 1]
res[i] = tmp_res
return res[n]
98. Validate Binary Search Tree
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
def helper(root, lower, upper):
if not root:
return True
return lower < root.val < upper and helper(root.left, lower, root.val) and helper(root.right, root.val, upper)
return helper(root, float("-inf"), float("inf"))
101. Symmetric Tree
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
def helper(left, right):
if not left and not right:
return True
if left and right:
return left.val == right.val and \
helper(left.left, right.right) and \
helper(left.right, right.left)
return False
if not root:
return True
return helper(root.left, root.right)
102. Binary Tree Level Order Traversal
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
def level_func(node_list):
tmp_node_list = []
for node in node_list:
if node.left:
tmp_node_list.append(node.left)
if node.right:
tmp_node_list.append(node.right)
return tmp_node_list
if not root:
return []
res = []
tmp_node_list = [root]
while len(tmp_node_list) > 0:
res.append([node.val for node in tmp_node_list])
tmp_node_list = level_func(tmp_node_list)
return res
104. Maximum Depth of Binary Tree
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
if not root.left and not root.right:
return 1
return max(self.maxDepth(root.left) + 1, self.maxDepth(root.right) + 1)
105. Construct Binary Tree from Preorder and Inorder Traversal
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
#preorder: root left right
#inorder: left root right
def build(preorder, inorder, preorder_start_index, preorder_end_index,
inorder_start_index, inorder_end_index):
if preorder_start_index >= preorder_end_index:
return
root = TreeNode(preorder[preorder_start_index])
right_set = set()
inorder_root_index = 0
for i in range(inorder_start_index, inorder_end_index):
if inorder[i] == preorder[preorder_start_index]:
inorder_root_index = i
right_set = set(inorder[i: inorder_end_index])
break
preorder_right_start_index = preorder_end_index
for i in range(preorder_start_index + 1, preorder_end_index):
if preorder[i] in right_set:
preorder_right_start_index = i
break
root.left = build(preorder, inorder, preorder_start_index + 1, preorder_right_start_index,
inorder_start_index, inorder_root_index)
root.right = build(preorder, inorder, preorder_right_start_index, preorder_end_index,
inorder_root_index, inorder_end_index)
return root
root = build(preorder, inorder, 0, len(preorder), 0, len(inorder))
return root
preorder是root left right,inorder是left root right,所以我们可以通过preorder的第一个root去inorder中找root位置,再找到preorder中right开始的位置,这样重新构建left和right。
看了答案发现有几个可以优化的地方,一个是可以建立index来方便找到位置,另一个是right开始的位置可以通过inorder中root位置得到left长度来回推。
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
index = {elem: i for i, elem in enumerate(inorder)}
def build(preorder, inorder, preorder_start_index, preorder_end_index,
inorder_start_index, inorder_end_index):
if preorder_start_index >= preorder_end_index:
return
root = TreeNode(preorder[preorder_start_index])
inorder_root_index = index[preorder[preorder_start_index]]
preorder_right_start_index = inorder_root_index - inorder_start_index + preorder_start_index + 1
root.left = build(preorder, inorder, preorder_start_index + 1, preorder_right_start_index,
inorder_start_index, inorder_root_index)
root.right = build(preorder, inorder, preorder_right_start_index, preorder_end_index,
inorder_root_index + 1, inorder_end_index)
return root
root = build(preorder, inorder, 0, len(preorder), 0, len(inorder))
return root