文章目录
- 1.两数之和
- 3. Longest Substring Without Repeating Characters
- 4. Median of Two Sorted Arrays
- 5.Longest Palindromic Substring
- 11.Container With Most Water
- 15. 3Sum:
- 17. Letter Combinations of a Phone Number
- 19. Remove Nth Node From End of List:
- 21. Merge Two Sorted Lists
- 22.Generate Parentheses
- 23.Merge k Sorted List:
- 31.Next Permutation
- 32. Longest Valid Parentheses
- 33.Search in Rotated Sorted Array:
- 34.Find First and Last Position of Element in Sorted Array
- 39.Combination Sum:
- 40.组合总和II:
- 41.缺失的第一个正数:
- 42.Trapping Rain Water
- 46.Permutations
- 48.Rotate Image
- 49. Group Anagrams
- 53.Maximum Subarray
- 55. Jump Game:
- 56. Merge Intervals
- 62. Unique Paths
- 64. Minimum Path Sum
- 70. Climbing Stairs
- 72. Edit Distance
- 75. Sort Colors
- 76. Minimum Window Substring
- 78. 子集
- 84. Largest Rectangle in Histogram
- 86.分割链表:
- 90.子集II:
- 94. Binary Tree Inorder Traversal
- 102. 二叉树的层次遍历:
- 104.二叉树的最大深度:
- 111. 二叉树的最小深度:
- 114.二叉树展开成链表:
- 121.Best Time to Buy and Sell Stock:
- 122. Best Time to Buy and Sell Stock II
- 128. Longest Consecutive Sequence
- 136.Single Number
- 137.只出现一次的数字 II
- 138. 复制带随机指针的链表:
- 141. Linked List Cycle
- 142. Linked List Cycle II
- 152.Maximum Product Subarray
- 155.Min Stack
- 160.Intersection of Two Linked Lists
- 169.求众数:
- 198.打家劫舍:
- 200. 岛屿的个数:
- 206.反转链表:
- 208.实现前缀树:
- 215.数组中的第k个最大元素
- 222.完全二叉树的节点:
- 226.翻转二叉树
- 232.用栈实现队列:
- 234.回文链表:
- 238.Product of Array Except Self
- 239.滑动窗口最大值
- 240.搜索二维矩阵 II:
- 264.丑数:
- 265.丑数II:
- 284.移动零:
- 287.寻找重复数
- 409.Longest Palindrome
- 438. 找到字符串中所有字母异位词
- 448.找到所有数组中消失的数字:
- 461.汉明距离:
- 494. 目标和
- 581.最短无序连续子数组:
- 617.合并二叉树:
- 647. Palindromic Substrings
- 771. Jewels and Stones
题目 | 难度 | 复杂度 | 解法 | 备注 | 话题 |
---|---|---|---|---|---|
1.两数之和 | Easy | O ( n 2 ) ; O ( n ) O(n^2);O(n) O(n2);O(n) | 暴力法;保存哈希表 | Done | 数组、哈希表 |
3. Longest Substring Without Repeating Characters | Medium | O ( n ) O(n) O(n) | 遍历哈希表保存每个字符的初始位置 | ToDo | |
4. Median of Two Sorted Arrays | Medium | O ( n l o g n ) , O ( l o g ( m i n ( m , n ) ) O(nlogn),O(log(min(m,n)) O(nlogn),O(log(min(m,n)) | 传统解法+中位数的数学推导 | ||
5.Longest Palindromic Substring | Medium | O ( n 3 ) O(n^3) O(n3) | 暴力解法,遍历然后判断每个子字符串是否为回文 | Done | |
11. Container With Most Water | Medium | O ( n 2 ) , O ( n ) O(n^2), O(n) O(n2),O(n) | 暴力解法获取每个区间,求最大;双指针,从外向里移动 | Done | |
15. 3Sum | Medium | O ( n l o g n ) , O ( n 2 ) O(nlogn),O(n^2) O(nlogn),O(n2) | 双指针 | ||
17. Letter Combinations of a Phone Number | Medium | 递归 | |||
19. Remove Nth Node From End of List | Medium | O ( n ) O(n) O(n) | 设置哑结点 | ||
21. Merge Two Sorted Lists | Easy | O ( m + n ) O(m+n) O(m+n) | 设置哑节点,然后类似list,依次选择较小的一个 | Done | 链表 |
22.Generate Parentheses | Medium | O ( 2 2 n n ) ; O(2^{2n}n); O(22nn); | 暴力做法;回溯法,前面的序列有效时才增加"(“或”)" | ||
23.Merge k Sorted Lists | Hard | O ( n l o g n ) O(nlogn) O(nlogn) | 暴力法;分置变成双链表问题 | ToDo | |
31.Next Permutation | Medium | O ( n ! ) O(n!) O(n!) | 暴力法;遍历,替换 | ToDo | |
32.Longest Valid Parentheses | Hard | O ( n 3 ) ; O ( n ) O(n^3);O(n) O(n3);O(n) | 暴力法;数学规律 | ToDo | |
33.Search bia Rotated Sorted Array | Medium | O ( n ) O(n) O(n) | 遍历; | Done | |
34.Find First and Last Position of Element in Sorted Array | Medium | O ( n ) ; O ( l o g n ) O(n);O(logn) O(n);O(logn) | 遍历;二分查找 | Done | |
39.Combination Sum | Medium | 递归 | ToDo | ||
41.缺失的第一个正数 | Hard | O ( n ) O(n) O(n) | 主要是边界情况 | Done | 数组 |
42. Trapping Rain Water | Hard | O ( n 2 ) ; O ( n ) O(n^2);O(n) O(n2);O(n) | 暴力;双指针 | ToDO | |
46.Permutations | Medium | 递归 | ToDo | ||
48. | Medium | O ( n 2 ) O(n^2) O(n2) | 翻转然后转置 | Done | |
53. Maximum Subarray | Easy | O ( n 2 ) ; O ( n ) O(n^2);O(n) O(n2);O(n) | 遍历所有子序列; | Done | |
55. Jump Game | Medium | O ( n ) O(n) O(n) | 贪心法,从右到左 | ToDo | |
56. Merge Intervals | Medium | O ( n l o g n ) O(nlogn) O(nlogn) | 排序,然后进行区间合并 | Done | |
62. Unique Paths | Medium | O ( m a x ( m , n ) ! ) ; O ( n 2 ) O(max(m,n)!);O(n^2) O(max(m,n)!);O(n2) | 一共m+n-2步,选择m-1种向下的走法;DP | ToDo | |
64. Minimum Path Sum | Medium | O ( ) O() O() | 动态规划 | ToDo | |
70.Climbing Stairs | Easy | O ( n ) O(n) O(n) | 斐波那契数列 | ToDo | |
72.Edit Distance | Hard | Medium | O ( n ) O(n) O(n) | 动态规划 | ToDo |
75. Sort Colors | Medium | O ( n ) O(n) O(n) | 直接排序,或者对0,2进行操作 | Done | |
76. Minimum Window Substring | Hard | O ( S + T ) O(S+T) O(S+T) | 双指针+滑动窗口 | ToDo | |
84. Largest Rectangle in Histogram | Hard | O ( n ) O(n) O(n) | ToDo | ||
86.分割链表 | Medium | O ( n ) O(n) O(n) | 设置两个临时结点 | Done | 链表 |
94. Binary Tree Inorder Traversal | Medium | 递归和非递归方法 | ToDo | ||
102.二叉树的层次遍历 | Medium | O ( N ) O(N) O(N) | 队列保存每个结点 | ToDo | 二叉树 |
114.二叉树展开成链表 | Medium | O ( N ) O(N) O(N) | 前序遍历然后保存在list中;inplace | ToDo | 二叉树 |
121. Best Time to Buy and Sell Stock | Easy | O ( n 2 ) ; O ( n ) O(n^2);O(n) O(n2);O(n) | 暴力; 一次遍历,依次当前值前面的最小值 | Done | |
122. Best Time to Buy and Sell Stock II | Easy | O ( n n ) ; O ( n ) O(n^n);O(n) O(nn);O(n) | 暴力法和一次遍历 | ToDo | |
128. Longest Consecutive Sequence | Hard | O ( n l o g n ) ; O ( n ) O(nlogn);O(n) O(nlogn);O(n) | 排序后遍历 | ToDo | |
136.只出现一次的数字 | Easy | O ( n ) O(n) O(n) | 哈希表;位操作;数学方法 | Done | 数组 |
137.只出现一次的数字II | Medium | O ( n ) O(n) O(n) | 哈希表;位操作;数学方法 | Done | 数组 |
138. 复制带随机指针的链表 | Medium | O O O | ToDo | 链表 | |
141. Linked List Cycle | Easy | O ( n ) O(n) O(n) | 哈希表或者快慢指针 | Done | 链表 |
142. Linked List Cycle II | Medium | O ( n 2 ) , O ( n ) O(n^2),O(n) O(n2),O(n) | 哈希表或者快慢指针 | Done | 链表 |
152.Maximum Product Subarray | Medium | O ( n 2 ) ; O ( n ) O(n^2);O(n) O(n2);O(n) | 暴力法;前后遍历,得到乘积 | Done | |
155. Min Stack | Easy | 建立辅助栈 | Done | ||
160.相交链表 | Easy | 保存前一个为set遍历另外一个,数学方法 | 遍历 | Done | 链表 |
169.求众数 | Easy | O ( n ) O(n) O(n) | 哈希表保存出现次数 | Done | |
198. 打家劫舍 | Easy | O n ( ) On() On() | 动态规划 | ToDo | |
200. 岛屿的个数 | Medium | DFS | ToDo | ||
206.反转链表 | Easy | O ( m ) O(m) O(m) | 交换既可 | Done | 链表 |
208.实现前缀树 | Medium | 直接实现 | Done | ||
215. 数组中的第K个最大元素 | Medium | O ( n l o g n ) O(nlogn) O(nlogn) | 排序,然后求解 | Done | |
221.最大正方形 | Medium | ToDo | |||
226.翻转二叉树 | Easy | O ( l o g n ) O(logn) O(logn) | 递归,翻转 | Done | |
234.回文链表 | Easy | O ( n ) O(n) O(n) | 保存在list中然后判断是否是回文 | Done | |
236.二叉树的最近公共祖先 | Medium | O ( n ) O(n) O(n) | ToDo | ||
238.除自身以外的数组的乘积 | Medium | O ( n ) O(n) O(n) | 除法;前后累积乘积 | ToDo | |
239.滑动窗口最大值 | Hard | O ( k n ) ; O ( n ) O(kn);O(n) O(kn);O(n) | 滑动遍历求最值; | Done | |
240.搜索二维矩阵 | Medium | O ( n 2 ) ; O ( n ) O(n^2);O(n) O(n2);O(n) | 观察规律 | Done | |
264丑数 | Easy | O ( n ) O(n) O(n) | 判断是否是2,3,5的倍数不断除 | Done | 数学 |
265.丑数II | Medium | 依次生成即可,保存较小的值 | Done | 数学 | |
279.完全平方数 | Medium | Todo | |||
283.移动零 | Medium | O ( n ) O(n) O(n) | 遍历,去除,保存 | Done | |
287.寻找重复数 | Medium | O ( n ) O(n) O(n) | 哈希表保存次数 | Done | |
297. 二叉树的序列化与反序列化 | Hard | Done | |||
300.最长上升子序列 | Medium | ToDo | |||
309.最佳买卖股票时机含冷冻期 | Medium | ToDo | |||
312. 戳气球 | Hard | ToDo | |||
322.零钱兑换 | Medium | 动态规划 | ToDo | ||
409. Longest Palindrome | Easy | O ( n 2 ) O(n^2) O(n2) | 统计次数,判断奇偶 | Done | |
461.汉明距离 | Easy | O ( n ) O(n) O(n) | 异或然后判断二进制中1的个数 | Done | |
494. 目标和 | Medium | DFS | ToDo | ||
581. 最短无序连续子数组 | Easy | O ( n l o g n ) O(nlogn) O(nlogn) | 排序然后遍历比较 | Done | |
617.合并二叉树 | Medium | O ( m ) O(m) O(m) | 递归;循环 | Done | |
647. 回文子串 | Medium | O ( n 3 ) , O ( n 2 ) O(n^3), O(n^2) O(n3),O(n2) | 暴力解法;遍历字符串以每个字符为中心 | Done | |
771. Jewels and Stones | Easy | O ( m n ) O(mn) O(mn) | 巨简单 |
1.两数之和
暴力法
哈希表
O
(
n
)
O(n)
O(n): 遍历数组将数组保存在哈希表中,key:num,value:index,然后再遍历数组,判断target-num是否在哈希表里面,保证该元素不能是他自身。
# 此方法需要遍历两边数组
class Solution(object):
# 56ms 93.92%
def twoSum(self, nums, target):
nums_dict = dict()
for index in range(len(nums)):
nums_dict[nums[index]] = index
for index in range(len(nums)):
temp = target-nums[index]
if temp in nums_dict and nums_dict[temp] != index:
return [index,nums_dict[temp]]
# 仅需遍历一遍数组的
class Solution(object):
def twoSum(self, nums, target):
nums_dict = dict()
for index in range(len(nums)):
temp = target-nums[index]
if temp in nums_dict:
return [index,nums_dict[temp]]
nums_dict[nums[index]] = index
3. Longest Substring Without Repeating Characters
暴力解法,遍历所有子字符串,然后判断所有字符串是否重复,求不重复的最大值
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
if s == '':
return 0
if len(s) == 1:
return 1
len_list = []
for i in range(len(s)-1):
for j in range(i+1, len(s)+1):
temp = s[i:j]
# print(temp)
if len(set(temp)) == len(temp):
len_list.append(len(temp))
return max(len_list)
用一个Hash表保存每一个char出现的位置,如果出现重复,那么将这个char重复出现的位置和第一次出现的位置相减。
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
char_dict = {}
start = 0
maxlen = 0
for index, char in enumerate(s):
if char in char_dict and char_dict[char] >= start:
maxlen = max(maxlen, index-start)
start = char_dict[char] + 1
char_dict[char] = index
return max(maxlen, len(s)-start)
4. Median of Two Sorted Arrays
暴力解法,4ms
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
nums1.extend(nums2)
length = len(nums1)
nums1 = sorted(nums1)
if len(nums1)%2 == 0:
return (nums1[int(length/2)-1] + nums1[int(length/2)])/2
else:
return nums1[int((length-1)/2)]
5.Longest Palindromic Substring
暴力解法,遍历然后判断是否是回文。
class Solution:
def longestPalindrome(self, string):
"""
:type s: str
:rtype: str
"""
length = len(string)
max_len = 0
result = ''
if len(string) == 1:
return string
for i in range(length):
for j in range(i+1,length+1):
temp = string[i:j]
# print(temp,i,j)
if temp == temp[::-1] and len(temp) > max_len:
max_len = len(temp)
result = temp
return result
遍历字符串,以单个字符为中心向外延展,取字符串长度最长的。考虑”aba“和”abba“这两种情况。
class Solution(object):
def longestPalindrome(self, s):
res = ""
for i in range(len(s)):
# odd case, like "aba"
tmp = self.helper(s, i, i)
if len(tmp) > len(res):
res = tmp
# even case, like "abba"
tmp = self.helper(s, i, i+1)
if len(tmp) > len(res):
res = tmp
return res
# get the longest palindrome, l, r are the middle indexes
# from inner to outer
def helper(self, s, l, r):
while l >= 0 and r < len(s) and s[l] == s[r]:
l -= 1; r += 1
return s[l+1:r]
11.Container With Most Water
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
maxarea = 0
for i in range(len(height)-1):
for j in range(i+1, len(height)):
area = (j-i)*min(height[i],height[j])
if area > maxarea:
maxarea = area
return maxarea
双指针,从两边向里移动,移动start和end中小的那一个
class Solution:
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
max_area,left,right = 0,0,len(height)-1
while(left < right):
max_area = max(max_area, (right-left)*min(height[left], height[right]))
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_area
15. 3Sum:
暴力解法, O ( n 3 ) O(n^3) O(n3)
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums) < 3:
return
result = []
nums = sorted(nums)
result_str = []
for i in range(len(nums) - 2):
for j in range(i+1, len(nums) - 1):
for k in range(j+1, len(nums)):
result1 = ''.join([str(nums[i]),str(nums[j]), str(nums[k])])
if nums[i] + nums[j] + nums[k] == 0 and result1 not in result_str:
result.append([nums[i],nums[j], nums[k]])
result_str.append(result1)
return result
双指针,做成Two-Sum问题:
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums = sorted(nums)
result = []
for i in range(len(nums)-2):
if i > 0 and nums[i] == nums[i-1]:
continue
left = i+1
right = len(nums) - 1
while left < right:
sum1 = nums[i] + nums[left] + nums[right]
if sum1 < 0:
left += 1
elif sum1 == 0:
result.append([nums[i],nums[left], nums[right]])
left += 1
right -= 1
while left < right and nums[left] == nums[left-1]:
left += 1
while right > left and nums[right] == nums[right+1]:
right -= 1
else:
right -= 1
return result
17. Letter Combinations of a Phone Number
采用递归来写,
class Solution(object):
def letterCombinations(self, digits):
"""
:type digits: str
:rtype: List[str]
"""
kvmaps = {
'2': 'abc',
'3': 'def',
'4': 'ghi',
'5': 'jkl',
'6': 'mno',
'7': 'pqrs',
'8': 'tuv',
'9': 'wxyz'
}
if len(digits) == 0:
return []
if len(digits) == 1:
return list(kvmaps[digits[0]])
return [str1 + char1 for str1 in self.letterCombinations(digits[:-1]) for char1 in kvmaps[digits[-1]]]
19. Remove Nth Node From End of List:
首先确定链表的长度L,删除倒数第N个,即删除正数第L-N+1个;
# 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):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
dummy = ListNode(0)
length = 0
dummy.next = head
first = head
while first != None:
length += 1
first = first.next
length -= n
first = dummy
while length > 0:
length -= 1
first = first.next
first.next = first.next.next
return dummy.next
两个指针,第一个指针走n个后,另一个指针再开始,第一个指针到最后的时候,第二个指针到达倒数第n个。
class Solution(object):
def removeNthFromEnd(self, head, n):
dummy = ListNode(0)
dummy.next = head
first = dummy
second = dummy
for i in range(n+1):
first = first.next
while first != None:
first = first.next
second = second.next
second.next = second.next.next
return dummy.next
21. Merge Two Sorted Lists
递归: 一次保存两个链表中较小 一个。
class Solution(object):
def mergeTwoLists(self, pHead1, pHead2):
# write code here
if pHead1 == None:
return pHead2
if pHead2 == None:
return pHead1
pMergeHead = None
if pHead1.val < pHead2.val:
pMergeHead = pHead1
pMergeHead.next = self.mergeTwoLists(pHead1.next, pHead2)
else:
pMergeHead = pHead2
pMergeHead.next = self.mergeTwoLists(pHead1, pHead2.next)
return pMergeHead
循环: 判断l1和l2是否为空,依次取较小的一个,然后合并l1和l2,有一个可能提前遍历完,直接拼接另一个即可。
class Solution(object):
def mergeTwoLists(self, l1, l2):
dummy = cur = ListNode(0)
while l1 and l2:
if l1.val < l2.val:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
cur.next = l1 or l2
return dummy.next
22.Generate Parentheses
暴力做法,生成所有的表示“()”字符构成的序列,然后判断该字符是否是有效的。通过递归来生成所有的序列。平衡字符来判断该序列是否是有效的。
class Solution(object):
# 148ms
# 13.5MB
def generateParenthesis(self, n):
def generate(A = []):
if len(A) == 2*n:
if valid(A):
ans.append("".join(A))
else:
A.append('(')
generate(A)
A.pop()
A.append(')')
generate(A)
A.pop()
def valid(A):
bal = 0
for c in A:
if c == '(': bal += 1
else: bal -= 1
if bal < 0: return False
return bal == 0
ans = []
generate()
return ans
回溯法:当当前序列有效时才增加新的括号“()”。判断的标准是左括号的数目,保证左括号数量小于N,如果右括号数量小于左括号数目那么增加右括号数目。
class Solution(object):
# 56ms
# 13.4MB
def generateParenthesis(self, N):
ans = []
def backtrack(S = '', left = 0, right = 0):
if len(S) == 2 * N:
ans.append(S)
return
if left < N:
backtrack(S+'(', left+1, right)
if right < left:
backtrack(S+')', left, right+1)
backtrack()
return ans
23.Merge k Sorted List:
暴力法 O ( n l o g n ) O(nlogn) O(nlogn):保存所有链表的数值,然后对其进行排序,将排序后的list转换成链表
class Solution(object):
# 88ms
# 20MB
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
all_list = []
head = point = ListNode(0)
for List in lists:
while List:
all_list.append(List.val)
List = List.next
all_list = sorted(all_list)
for num in all_list:
point.next = ListNode(num)
point = point.next
return head.next
分置算法:
将这k个排序链表一分为二,不断持续下去,将其变成双链表合并问题。
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
if not lists:
return []
if len(lists) == 1:
return lists[0]
mid = len(lists) // 2
ll = self.mergeKLists(lists[:mid])
rl = self.mergeKLists(lists[mid:])
return self.merge2List(ll,rl)
def merge2List(self, l, r):
root = ListNode(0)
cur = root
while l and r:
if l.val < r.val:
cur.next = l
l = l.next
cur = cur.next
else:
cur.next = r
r = r.next
cur = cur.next
if l:
cur.next = l
else:
cur.next = r
return root.next
31.Next Permutation
暴力法:
生成所有可能的排列情况,然后找到最接近的那个排列。
从右到左遍历list,如果第i个数比第i+1数小,那么这个数应该被替换。这个数的右边是一个递减序列。将这个数替换成右边序列比第i个数大,但最接近的那个。然后将右边的数做逆序排列。
class Solution:
def nextPermutation(self, nums):
"""
:type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead.
"""
i = len(nums) - 2
while i >= 0 and nums[i] >= nums[i+1]:
i -= 1
if i>=0:
j = len(nums) - 1
while j >=0 and nums[i] >= nums[j]:
j -= 1
temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
nums[i+1:] = nums[i+1:][::-1]
32. Longest Valid Parentheses
暴力法,生成所有的子序列,然后判断是否是有效序列,保存有效序列的长度,求最值:
class Solution:
def longestValidParentheses(self, s):
"""
:type s: str
:rtype: int
"""
def Isvalid(s):
num = 0
for char in s:
if char == '(':
num += 1
else:
num -= 1
if num < 0:
return False
return num == 0
result = []
for i in range(len(s)-1):
for j in range(i+1, len(s)+1):
temp_s = s[i:j]
if Isvalid(temp_s):
result.append(len(temp_s))
if result == []:
return 0
return max(result)
利用数学规律,首先从左到右遍历,遇到“(”,left+1,遇到")",right+1。如果left和right再次相等,则为有效序列,判断其是否为最长序列,同时令left和right均为0,如果right>left也置零。从右到左做同样的遍历。
# 52 ms
# 13.2 Mb
class Solution(object):
def longestValidParentheses(self, s):
"""
:type s: str
:rtype: int
"""
left,right,maxlength = 0,0,0
for i in range(len(s)):
if s[i] == '(':
left += 1
else:
right += 1
if left == right:
maxlength = max(maxlength, 2*right)
elif right > left:
left = 0
right = 0
left = right = 0
for i in range(len(s)-1,-1,-1):
if s[i] == '(':
left += 1
else:
right += 1
if left == right:
maxlength = max(maxlength, 2*left)
elif left >= right:
left = right = 0
return maxlength
33.Search in Rotated Sorted Array:
遍历list,然后得到index:
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
if target not in nums:
return -1
return nums.index(target)
二分法:
和旋转数组寻找最小值不一样,只要判断middle和left,right的大小即可。这要分成多种情况讨论。旋转点在middle右侧和旋转点在middle左侧,然后又分为两种情况。
class Solution:
# @param {integer[]} numss
# @param {integer} target
# @return {integer}
def search(self, nums, target):
if not nums:
return -1
low, high = 0, len(nums) - 1
while low <= high:
mid = (low + high) >> 1
if target == nums[mid]:
return mid
if nums[low] <= nums[mid]:
if nums[low] <= target <= nums[mid]:
high = mid - 1
else:
low = mid + 1
else:
if nums[mid] <= target <= nums[high]:
low = mid + 1
else:
high = mid - 1
return -1
def search(self, nums, target):
lo, hi = 0, len(nums) - 1
while lo < hi:
mid = (lo + hi) / 2
if (nums[0] > target) ^ (nums[0] > nums[mid]) ^ (target > nums[mid]):
lo = mid + 1
else:
hi = mid
return lo if target in nums[lo:lo+1] else -1
34.Find First and Last Position of Element in Sorted Array
暴力做法,找到所有满足条件的数字,然后求index的最大最小值
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
result = [index for index,item in enumerate(nums) if item == target]
if len(result) == 0:
result = [-1, -1]
return [min(result),max(result)]
双指针,在整个list范围,建立两个指针,从两头开始遍历:
# 108ms
# 12.9MB
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
if nums == []:
return [-1,-1]
left,right = 0,len(nums)-1
while nums[left] != target or nums[right]!=target:
if nums[left] != target:
left += 1
if nums[right] != target:
right -= 1
if left > right:
return [-1,-1]
return [left,right]
先找第一个和target相等的点(通过遍历来寻找),然后找最后一个和target相等点:
# 40ms
# 13.8MB
class Solution(object):
def searchRange(self, nums, target):
first, last = 0, 0
i, j = 0, 0
for i in range(len(nums)):
if nums[i] == target:
first = i
break
else:
return [-1, -1]
for j in range(i+1, len(nums)):
if nums[j] != target:
last = nums[j-1]
return [i, j-1]
else:
return [i, j or i]
分别查找和target相等的第一个点和最后一个点,采用二分查找而不是遍历。
class Solution:
# returns leftmost (or rightmost) index at which `target` should be inserted in sorted
# array `nums` via binary search.
def extreme_insertion_index(self, nums, target, left):
lo = 0
hi = len(nums)
while lo < hi:
mid = (lo + hi) // 2
if nums[mid] > target or (left and target == nums[mid]):
hi = mid
else:
lo = mid+1
return lo
def searchRange(self, nums, target):
left_idx = self.extreme_insertion_index(nums, target, True)
# assert that `left_idx` is within the array bounds and that `target`
# is actually in `nums`.
if left_idx == len(nums) or nums[left_idx] != target:
return [-1, -1]
return [left_idx, self.extreme_insertion_index(nums, target, False)-1]
39.Combination Sum:
知道采用递归,但是依然不太会,懵逼。
class Solution(object):
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
candidates = sorted(candidates)
def combine(start,target):
answer=[]
for i in range(start,len(candidates)):
if target<candidates[i]:
break
if target==candidates[i]:
answer.append([target])
break
for item in combine(i,target-candidates[i]):
item.append(candidates[i])
answer.append(item)
return answer
return combine(0,target)
40.组合总和II:
此题不能用循环,因为求和不等于target就不会保存在result里面,后续遍历就获取不到。
41.缺失的第一个正数:
常规法:首先对数组取set,然后从1开始遍历,判断是否在数组里面。注意边界情况:[1,2,3,4],[ ],[-1,-2,-3],[-5]
class Solution(object):
def firstMissingPositive(self, nums):
if len(nums) == 0:
return 1
nums = set(nums)
num = 1
while num <= max(nums):
if num not in nums:
return num
num += 1
return max(1, max(nums) + 1)
42.Trapping Rain Water
暴力:遍历数组,求每个柱子上面能留存的最多的水,也就是 m i n ( m a x l e f t , m a x r i g h t ) − h e i g h t [ i ] min(maxleft,maxright) - height[i] min(maxleft,maxright)−height[i]
class Solution(object):
# 超时
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
ans = 0
size = len(height)
for i in range(1, size-1):
max_left,max_right = 0,0
for j in range(i, -1, -1):
max_left = max(max_left, height[j])
for j in range(i, size):
max_right = max(max_right, height[j])
ans += min(max_left, max_right) - height[i]
return ans
双指针,left和right两个指针,设left_max和right_max两个标志位。只要height[left]不大于left_max,那么留存的水便是left_max - height[left]。right如是操作。
class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
left ,right = 0,len(height)-1
ans = 0
left_max, right_max = 0,0
while left < right:
if height[left] < height[right]:
if height[left] >= left_max:
left_max = height[left]
else:
ans += left_max - height[left]
left += 1
else:
if height[right] > right_max:
right_max = height[right]
else:
ans += right_max - height[right]
right -= 1
return ans
46.Permutations
生成数组的全排列。采用递归,遍历数组的每一个字符,然后去除这个字符,递归这个函数。
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if nums is None: return []
if len(nums) == 1: return [nums]
res = []
for x in nums:
ys=nums+[]
ys.remove(x)
for y in self.permute(ys):
res.append([x]+y)
return res
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
ans = []
if len(nums) == 0:
return
if len(nums) == 1:
return [nums]
for index,item in enumerate(nums):
res = nums[:index]+nums[index+1:] #剩余的数字集合
for j in self.permute(res): #对剩余的数字进行递归
ans.append(j+[item])
return ans
48.Rotate Image
旋转90°相当于首先对矩阵进行reverse然后进行转置。
class Solution:
def rotate(self, A):
A.reverse()
for i in range(len(A)):
for j in range(i):
A[i][j], A[j][i] = A[j][i], A[i][j]
非常精彩的代码,一行结束。和上面做法是一样的,但是语法更简洁。
class Solution:
def rotate(self, A):
A[:] = map(list, zip(*A[::-1]))
49. Group Anagrams
建立一个Hash表,key是每个string排序后的结果,value是一个list保存key相同的string。
class Solution(object):
def groupAnagrams(self, strs):
"""
:type strs: List[str]
:rtype: List[List[str]]
"""
result = {}
for str1 in strs:
try:
result[''.join(sorted(str1))] += [str1]
except:
result[''.join(sorted(str1))] = [str1]
return list(result.values())
# 与上面的方法一样,但是采用collections类
class Solution(object):
def groupAnagrams(self, strs):
ans = collections.defaultdict(list)
for s in strs:
ans[tuple(sorted(s))].append(s)
return ans.values()
53.Maximum Subarray
遍历所有子序列,然后求和比较最大值。
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
max_sum = -1e10
length = len(nums)
for i in range(length):
for j in range(i+1, length+1):
temp = sum(nums[i:j])
if temp > max_sum:
max_sum = temp
return max_sum
遍历依次数组,比较从前面某一点开始到当前值的求和和当前值的大小。保证到当前值的子序列都是最大的。
class Solution:
# @param A, a list of integers
# @return an integer
# 6:57
def maxSubArray(self, A):
if not A:
return 0
curSum = maxSum = A[0]
for num in A[1:]:
curSum = max(num, curSum + num)
maxSum = max(maxSum, curSum)
return maxSum
55. Jump Game:
采用贪心,从最后一个值出发,向前找第一个能到达这个有效值的点。依次判断每个点是否是一个有效点,称为Good Position,否则为Bad Position。判断最后一个有效点是否是零点。
class Solution(object):
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
length = len(nums)
lastPos = length - 1
for i in range(length-1, -1,-1):
if nums[i] + i >= lastPos:
lastPos = i
return lastPos == 0
56. Merge Intervals
首先根据第一个字符对其进行排序,然后判断每个区间的end值是否大于下一个区间的start值,如果大于等于则进行合并。否则直接拼接在result里面即可。
def merge(intervals):
"""
:type intervals: List[Interval]
:rtype: List[Interval]
"""
# 执行用时 : 96 ms
# 内存消耗 : 16.4 MB
intervals = sorted(intervals, key=lambda x:x[0])
result = []
for list1 in intervals:
# result为空则
if not result or result[-1][1] < list1[0]:
result.append(list1)
else:
result[-1][1] = list1[1]
return result
62. Unique Paths
一个非常秀的做法。从起始点到终点,一共m+n-2步,其中m-1步向下,n-1步向左。所以可以认为是个组合问题,从m+n-2步中选择m-1步作为向下的,也就是 C m + n − 2 m − 1 C^{m-1}_{m+n-2} Cm+n−2m−1。
class Solution(object):
def uniquePaths(self, m, n):
"""
:type m: int
:type n: int
:rtype: int
"""
return math.factorial(m+n-2)/math.factorial(m-1)/math.factorial(n-1)
动态规划,软肋,始终无法真正弄懂DP
class Solution(object):
def uniquePaths(self, m, n):
table = [[0 for x in range(n)] for x in range(m)]
for i in range(m):
table[i][0] = 1
for i in range(n):
table[0][i] = 1
for i in range(1,m):
for j in range(1,n):
table[i][j] = table[i-1][j] + table[i][j-1]
return table[m-1][n-1]
64. Minimum Path Sum
动态规划求解,2333,贼烦。
class Solution(object):
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
table = [[0 for x in range(n)] for x in range(m)]
for i in range(m):
table[i][0] = 1
for i in range(n):
table[0][i] = 1
for i in range(1,m):
for j in range(1,n):
table[i][j] = table[i-1][j] + table[i][j-1]
return table[m-1][n-1]
70. Climbing Stairs
斐波那契数列问题。
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n == 1:
return 1
if n == 2:
return 2
m1 = 1
m2 = 2
for i in range(2,n):
temp = m2
m2 = m2 + m1
m1 = temp
return m2
72. Edit Distance
编辑距离
class Solution(object):
# O(m*n) space
def minDistance(self, word1, word2):
l1, l2 = len(word1)+1, len(word2)+1
dp = [[0 for _ in xrange(l2)] for _ in xrange(l1)]
for i in xrange(l1):
dp[i][0] = i
for j in xrange(l2):
dp[0][j] = j
for i in xrange(1, l1):
for j in xrange(1, l2):
dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+(word1[i-1]!=word2[j-1]))
return dp[-1][-1]
75. Sort Colors
其实就是对列表进行排序
# 36ms
# 11.6Mb
class Solution(object):
def sortColors(self, nums):
nums.sort()
遍历一次list,遇到0就把他插入到list的第一个位置,遇到2就把他插入到list的最后位置
# 32ms
# 11.7Mb
class Solution(object):
def sortColors(self,nums):
n = len(nums)
index = 0
index2 = 0
while index < n-index2:
if nums[index]==0:
nums.pop(index)
nums.insert(0,0)
index += 1
elif nums[index]==2:
nums.pop(index)
nums.append(2)
index2 += 1
else:
index += 1
76. Minimum Window Substring
from collections import Counter
class Solution(object):
def minWindow(self,s ,t):
# 建立一个字典,保存每个字符出现的次数
dict_t = Counter(t)
# 需要满足的次数,即非重复的字符数
required = len(dict_t)
# 记录当前窗口满足的条件数,
formed = 0
left, right = 0,0
# ans是一个tuple,记录字符串子字符串长度和起始点
ans = float('inf'),0,0
# 当前窗口的字符的频率的统计
window_count = {}
while right < len(s):
char = s[right]
window_count[char] = window_count.get(char,0) + 1
# 如果满足以下条件,满足的条件数即加1
if char in window_count and window_count[char] == dict_t[char]:
formed += 1
# 如果条件均满足那么缩减窗口大小
while left <= right and formed == required:
char = s[left]
# 替换窗口长度,取最小值
if right - left + 1 < ans[0]:
ans = right - left + 1,left,right
window_count[char] -= 1
# 如果去掉一个字符后,依然满足条件,继续进行,如果不满足条件将formed-1
if char in dict_t and window_count[char] < dict_t[char]:
formed -= 1
left += 1
right += 1
return "" if ans[0] == float("inf") else s[ans[1] : ans[2] + 1]
78. 子集
循环: 遍历nums,然后遍历result,将reuslt的每一个list和nums里面的元素做拼接。nums每增加一个新元素,都对result中的元素进行拼接,然后和初始的result拼接在一起。 O ( n ) O(n) O(n)
def subsets(self, nums):
# 36ms
# 11.7Mb
result = [[]]
for num in nums:
result += [item + [num] for item in result]
return result
DFS:
class Solution(object):
def subsets(self, nums):
res = []
self.dfs(sorted(nums), 0, [], res)
return res
def dfs(self, nums, start, path, res):
res.append(path)
for i in range(start, len(nums)):
self.dfs(nums, i+1, path+[nums[i]], res)
class Solution(object):
def subsets(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
self.result = []
self.generate(nums,[],0)
return self.result
def generate(self,nums,item,index):
if index == len(nums):
self.result.append(item)
return
self.generate(nums, item+[nums[index]], index+1)
self.generate(nums, item, index+1)
84. Largest Rectangle in Histogram
暴力法求所有的子间隔的面积,然后求最大值。
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
length = len(heights)
left,right = 0,length
maxarea = 0
for i in range(length):
for j in range(i+1, length+1):
area = min(heights[i:j]) * (j-i)
maxarea = max(area, maxarea)
return maxarea
依然看不太懂,思路明白但是实现方式不太懂,对于栈的一些知识不太了解。
https://blog.youkuaiyun.com/Zolewit/article/details/88863970
def largestRectangleArea(self, height):
height.append(0)
stack = [-1]
ans = 0
for i in xrange(len(height)):
while height[i] < height[stack[-1]]:
h = height[stack.pop()]
w = i - stack[-1] - 1
ans = max(ans, h * w)
stack.append(i)
height.pop()
return ans
86.分割链表:
巧用临时结点,设置两个链表分别保存大于和小于x的结点。然后将两个临时结点连接起来。
class Solution:
# 36ms 89.86%
# 11.7 MB 38.12%
def partition(self, head, x):
if head == None or head.next == None:
return head
cur = head
pre_min = cur_min = ListNode(-1)
pre_max = cur_max = ListNode(-1)
while cur != None:
if cur.val < x:
cur_min.next = cur
cur_min = cur_min.next
else:
cur_max.next = cur
cur_max = cur_max.next
cur = cur.next
cur_min.next = pre_max.next
cur_max.next = None
return pre_min.next
90.子集II:
循环: 和78题类似,只不过在增加新的子集的时候判断是否在已知的里面,这可以解决同序重复问题([1,2,2],[1,2,2])。排序后可以解决不同序重复问题([1,2,2],[2,1,2])。
class Solution(object):
def subsetsWithDup(self, nums):
result = [[]]
for num in sorted(nums):
result += [i+[num] for i in result if i+[num] not in result]
return result
94. Binary Tree Inorder Traversal
递归方法实现:
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
ans=[]
if root==None:
return ans
def dfs(root):
if root==None:
return
dfs(root.left)
ans.append(root.val)
dfs(root.right)
return
dfs(root)
return ans
非递归方法:
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
#非递归方法
stack=[]
ans=[]
while(root or stack):
while(root):
stack.append(root)
root=root.left
root=stack.pop()
ans.append(root.val)
root=root.right
return ans
102. 二叉树的层次遍历:
用queue依次保存树的结点,向下遍历,依次保存每层的结点。每次遍历一次queue,相当于遍历依次上一层的所有结点,遍历一个结点便取出一个结点,直到queue为空为止。
class Solution(object):
def levelOrder(self, root):
if root is None:
return
queue=[root]
res=[]
while queue:
tem=[]
for i in range(len(queue)):
cur_node = queue.pop(0)
tem.append(cur_node.val)
if cur_node.left is not None:
queue.append(cur_node.left)
if cur_node.right is not None:
queue.append(cur_node.right)
res.append(tem)
return res
104.二叉树的最大深度:
递归,寻找递归关系。如果根节点不为空,那么返回两颗子树最大深度的最大值然后加1.
class Solution(object):
def maxDepth(self, root):
if root == None:
return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1
111. 二叉树的最小深度:
利用递归,如果根节点为空那么返回o。如果左右子树一个为空,返回另一个子树的mindepth同时+1.如果左右子树均不为空,则返回两棵树min(mindepth1, mindepth2) + 1
。
class Solution:
# @param root, a tree node
# @return an integer
def minDepth(self, root):
if root == None:
return 0
if root.left==None or root.right==None:
return self.minDepth(root.left)+self.minDepth(root.right)+1
return min(self.minDepth(root.right),self.minDepth(root.left))+1
114.二叉树展开成链表:
保存在list中然后链接成链表:前序遍历保存每个结点,然后将结点相连。
class Solution(object):
def preorder(self,root,result):
if root == None:
return
result.append(root)
self.preorder(root.left, result)
self.preorder(root.right, result)
return result
def flatten(self, root):
if root == None:
return []
result = []
result = self.preorder(root, result)
for index in range(1,len(result)):
result[index-1].left = None
result[index-1].right = result[index]
return result
inplace变换:
121.Best Time to Buy and Sell Stock:
使用暴力法进行遍历,后面的和前面比。
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
max_sum = 0
length = len(prices)
for i in range(length-1):
for j in range(i+1, length):
max_sum = max(max_sum, prices[j]-prices[i])
return max_sum
遍历依次列表,保存一直到当前数值,遇到的最小值,用遍历的值减去最小值,求最大。相当于求每个值和前面最小值的差(这个值通过遍历依次保存),然后求这个差的最大值。
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
maxsum = 0
length = len(prices)
minprice = 1e10
for num in prices:
if num < minprice:
minprice = num
maxsum = max(maxsum, num-minprice)
return maxsum
122. Best Time to Buy and Sell Stock II
暴力法,太复杂。
一次遍历,我们应该保存每一次相邻的波峰和波谷,多个相邻的波峰和波谷的差求和,要大于最优的选择(上题的最优解)。最极端的例子是12345类似的连续的序列,多个波峰波谷求和和最优单解相同。
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
if prices == []:
return 0
i,valley,peak = 0,prices[0],prices[0]
maxprofit = 0
length = len(prices)
while i < length -1:
# 如果当前值大于下一个值就一直往前走,找波谷
while i < length - 1 and prices[i] >= prices[i+1]:
i += 1
valley = prices[i]
# 如果当前值小于下一个值就一直走,找波峰
while i < length - 1 and prices[i] <= prices[i+1]:
i += 1
peak = prices[i]
maxprofit += peak - valley
print(maxprofit)
return maxprofit
128. Longest Consecutive Sequence
暴力法,排序后然后依次遍历。注意边界情况nums为空。注意去重,存在重复值排序后会存在bug。
class Solution(object):
def longestConsecutive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) == 0:
return 0
nums = sorted(set(nums))
maxlen = 1
temp = 1
for i in range(len(nums)-1):
if nums[i+1] - nums[i] == 1:
temp += 1
else:
temp = 1
maxlen = max(temp, maxlen)
return maxlen
将序列保存成一个set(python的查找复杂度是 O ( 1 ) O(1) O(1)),找到连续序列开头的第一个值,然后依次判断后面的值是否在nums里面。
class Solution(object):
def longestConsecutive(self, nums):
maxlen = 0
nums = set(nums)
for num in nums:
# 找到连续序列开头的第一个值
if num-1 not in nums:
cur_num = num
cur_len = 1
# 求后面序列的长度,这一步判断是O(1)
while cur_num + 1 in nums:
cur_num += 1
cur_len += 1
maxlen = max(maxlen, cur_len)
return maxlen
136.Single Number
**哈希表:**保存每个数出现的次数;
class Solution(object):
def singleNumber(self, nums):
num_count = {}
for num in nums:
num_count[num] = num_count.get(num,0) + 1
for key,value in num_count.items():
if value == 1:
return key
位操作: 一个数和0异或是他本身,两个相同的数异或是0;
class Solution(object):
# 100ms
def singleNumber(self, nums):
a = 0
for i in nums:
a ^= i
return a
数学: 很秀的操作:
return 2 * sum(set(nums)) - sum(nums)
137.只出现一次的数字 II
**哈希表:**保存每个数出现的次数,这个操作和上题一样。
class Solution(object):
def singleNumber(self, nums):
num_count = {}
for num in nums:
num_count[num] = num_count.get(num,0) + 1
for key,value in num_count.items():
if value == 1:
return key
数学: 依然是骚操作;
return (3*sum(set(nums)) - sum(nums))//2
138. 复制带随机指针的链表:
141. Linked List Cycle
奇葩值: 判断链表中是否有环,将链表中的元素设为某个奇葩值,如果链表元素会等于这个奇葩值,那么就是有环;
class Solution(object):
# 44ms
def hasCycle(self, head):
while head:
if head.val == 'like':
return True
else:
head.val = 'like'
head = head.next
return False
快慢指针: 建立两个指针,快指针和慢指针,快指针在前面,如果快指针后来超过了慢指针那么就是有环的,否则没有;
class Solution(object):
def hasCycle(self, head):
if head == None or head.next == None:
return False
slow = head
fast = head.next
while slow != fast:
if fast == None or fast.next == None:
return False
slow = slow.next
fast = fast.next.next
return True
建立set保存结点:遍历结点如果该结点在set中出现过么肯定有环。
class Solution(object):
# 88ms
def hasCycle(self, head):
node_set = set()
while head:
if head not in node_set:
node_set.add(head)
else:
return True
head = head.next
return False
142. Linked List Cycle II
建立一个哈希表保存链表中已经出现的结点,如果结点出现重复则判定为循环节。2333字典的查找速度要快于set????
class Solution(object):
# 60ms
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
unique_dict = {}
while head:
if head in unique_dict:
return head
unique_dict[head] = ''
head = head.next
class Solution(object):
# 64ms
def detectCycle(self, head):
head_set = set()
while head:
if head in head_set:
return head
else:
head_set.add(head)
head = head.next
方法二:详细解释 + python实现 设置快慢指针,如果存在环那么两个指针肯定会相遇,设相遇点是meet。可通过数学方法证明,一个从head(头)出发,一个从meet(相遇点)出发,他们的相遇点即环的起点。
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
try:
fast = head.next.next
slow = head.next
while fast != slow:
slow = slow.next
fast = fast.next.next
except:
return None
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
152.Maximum Product Subarray
暴力法:
class Solution(object):
def maxProduct(self, nums):
maxProd = -1e10
for i in range(len(nums)):
for j in range(i+1, len(nums)+1):
temp = 1
for k in range(i,j):
temp *= nums[k]
maxProd = max(maxProd, temp)
return maxProd
从前到后遍历,依次乘积的结果保存在list中相应的位置,主要解决的是0和负数的问题。最大值的情况,一定是从两头开始的,所以需要两头都需要考虑。
class Solution(object):
def maxProduct(self, A):
"""
:type nums: List[int]
:rtype: int
"""
B = A[::-1]
for i in range(1,len(A)):
A[i] *= A[i-1] or 1
B[i] *= B[i-1] or 1
return max(max(A),max(B))
155.Min Stack
求得栈的最小值,时间复杂度是O(1) O(1)O(1)。建立一个辅助栈,每增加一个数,保存目前所有数的最小值在辅助栈的栈顶。
注意:辅助栈(minStack)何时入栈,出栈的时候注意边界值。
class MinStack(object):
# 运行时间:23ms
# 占用内存:5752k
def __init__(self):
self.stack = []
self.minStack = []
def push(self, node):
# write code here
self.stack.append(node)
if self.minStack == [] or node < self.getMin():
self.minStack.append(node)
else:
temp = self.getMin()
self.minStack.append(temp)
def pop(self):
# write code here
if self.stack == None or self.minStack == None:
return None
self.minStack.pop()
self.stack.pop()
def top(self):
# write code here
return self.stack[-1]
def getMin(self):
# write code here
return self.minStack[-1]
160.Intersection of Two Linked Lists
建立set,然后将链表A结点均保存在set中,遍历链表B,返回在set中的第一个结点,如果没有返回None:
class Solution(object):
# 276ms 67.05%
# 42mb
def getIntersectionNode(self, headA, headB):
head_set = set()
while headA:
head_set.add(headA)
headA = headA.next
while headB:
if headB in head_set:
return headB
headB = headB.next
return None
求两个链表的长度,然后求其链表长度差,两个链表补齐后,遍历两个链表直到两个链表相等,即可返回,否则返回None。
class Solution(object):
def get_length(self, head):
# 求链表长度
length = 0
while head:
length += 1
head = head.next
return length
def getIntersectionNode(self, headA, headB):
if headA == None or headB == None:
return None
lenA = self.get_length(headA)
lenB = self.get_length(headB)
diff = abs(lenB - lenA)
if lenB > lenA:
for _ in range(diff):
headB = headB.next
else:
for _ in range(diff):
headA = headA.next
for _ in range(min(lenA,lenB)):
if headA == headB:
return headA
headA = headA.next
headB = headB.next
return None
直到两个相等,否则一直遍历。
class Solution:
def getIntersectionNode(self, headA, headB):
if headA is None or headB is None:
return None
pa = headA # 2 pointers
pb = headB
while pa is not pb:
# if either pointer hits the end, switch head and continue the second traversal,
# if not hit the end, just move on to next
pa = headB if pa is None else pa.next
pb = headA if pb is None else pb.next
return pa # only 2 ways to get out of the loop, they meet or the both hit the end=None
169.求众数:
出现次数超过一半的数;
排序: 对原list排序后返回中间的数。
class Solution(object):
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums = sorted(nums)
return nums[len(nums)//2]
哈希表: 遍历list然后将次数保存在哈希表。时间: O ( n ) O(n) O(n); 空间: O ( n ) O(n) O(n)
class Solution(object):
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
num_count = {}
for num in nums:
num_count[num] = num_count.get(num,0) + 1
length = len(nums)//2
for key,value in num_count.items():
if value > length:
return key
return -1
加减法: 因为肯定有一个数超过一半,用count来进行计数,如果下一个值和之前保留的值相同那么+1,否则-1,最后留下的一定是超过一半的数;时间 O ( n ) O(n) O(n);空间 O ( 1 ) O(1) O(1)
class Solution:
def majorityElement(self, nums):
count = 0
result = None
for num in nums:
if count == 0:
result = num
count += (1 if result == num else -1)
return result
198.打家劫舍:
采用递归求解,判断好结束条件,然后写递推公式即可,但是超时。
class Solution(object):
def rob(self, nums):
if len(nums) == 0:
return 0
if len(nums) <= 2:
return max(nums)
num2 = nums[1]
num1 = nums[0] + self.rob(nums[2:])
if len(nums) >= 4:
num2 += self.rob(nums[3:])
return max(num1, num2)
采用动态规划,依然不是很懂,解法.
class Solution:
# @param num, a list of integer
# @return an integer
def rob(self, num):
max_3_house_before, max_2_house_before, adjacent = 0, 0, 0
for cur in num:
max_3_house_before, max_2_house_before, adjacent = \
max_2_house_before, adjacent, max(max_3_house_before+cur, max_2_house_before+cur)
return max(max_2_house_before, adjacent)
200. 岛屿的个数:
class Solution():
def numIslands(self, grid):
def sink(i, j):
if 0 <= i < len(grid) and 0 <= j < len(grid[i]) and grid[i][j] == '1':
grid[i][j] = '0'
map(sink, (i+1, i-1, i, i), (j, j, j+1, j-1))
return 1
return 0
return sum(sink(i, j) for i in range(len(grid)) for j in range(len(grid[i])))
206.反转链表:
原链表的的第一个值的next必然是None,所以首先设一个链表为None(返回的答案)。然后依次遍历head,将head保存在prev里面,同时将prev的next指向prev,利用了python能同时赋值的特性,不必再设置别的变量来保存prev。这是最简单的写法,分开写比较麻烦。
class Solution(object):
def reverseList(self, head):
prev = None
while head:
prev,prev.next,head = head,prev,head.next
return prev
分开写:
class Solution(object):
def reverseList(self, head):
prev = None
while head:
temp = head.next
head.next = prev
prev = head
head = temp
return prev
208.实现前缀树:
直接实现即可,建立一个list,然后完成相应的功能。
class Trie(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.trie =[]
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str
:rtype: None
"""
self.trie.insert(0,word)
def search(self, word):
"""
Returns if the word is in the trie.
:type word: str
:rtype: bool
"""
if word in self.trie:
return True
else:
return False
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
:type prefix: str
:rtype: bool
"""
length = len(prefix)
flag = False
for strings in self.trie:
if prefix == strings[:length]:
flag = True
return flag
215.数组中的第k个最大元素
作弊操作,调用内部函数。应该自己写快排尝试解决。
class Solution(object):
# 72 ms
# 12.2Mb
def findKthLargest(self, nums, k):
return sorted(nums)[-k]
222.完全二叉树的节点:
利用递归,只要建立好递推关系式和终止条件,其他都好说。
class Solution(object):
def countNodes(self, root):
if root == None:return 0
return self.countNodes(root.left) + self.countNodes(root.right) + 1
226.翻转二叉树
通过递归来实现,对左子树和右子树执行相同的操作,然后交换左右子树。
class Solution(object):
# 32 ms
# 11.8Mb
def invertTree(self, root):
if root == None:
return None
if root.left != None:
root.left = self.invertTree(root.left)
if root.right != None:
root.right = self.invertTree(root.right)
root.right,root.left = root.left,root.right
return root
232.用栈实现队列:
2333直接用list实现的,貌似作弊?
class MyQueue(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.queue = []
def push(self, x):
"""
Push element x to the back of queue.
:type x: int
:rtype: None
"""
self.queue.append(x)
def pop(self):
"""
Removes the element from in front of queue and returns that element.
:rtype: int
"""
return self.queue.pop(0)
def peek(self):
"""
Get the front element.
:rtype: int
"""
return self.queue[0]
def empty(self):
"""
Returns whether the queue is empty.
:rtype: bool
"""
return self.queue == []
234.回文链表:
class Solution(object):
# 96 ms
# 31.6Mb
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
list1 = []
while head:
list1.append(head.val)
head = head.next
for i in range(len(list1)//2):
if list1[i] != list1[len(list1)-1-i]:
return False
return True
238.Product of Array Except Self
重点是统计0的个数。没有0,用除法即可。有一个0,那么有一个数不为0,其他均为0。有两个及以上的0,所有都是0.
class Solution(object):
def productExceptSelf(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
zeroNum = 0
product = 1
for num in nums:
if num == 0:
zeroNum += 1
else:
product *= num
for i in range(len(nums)):
if nums[i] == 0 and zeroNum == 1:
nums[i] = product
elif zeroNum == 0:
nums[i] = product/nums[i]
else:
nums[i] = 0
return nums
little trick,从左到右遍历,保存每个数前面所有的数的乘积。从右到左遍历,相当于保存这个数后面所有数的乘积。所有遍历两次数组,即可求出当前这个数前面所有数和后面所有数的乘积。
class Solution:
# @param {integer[]} nums
# @return {integer[]}
def productExceptSelf(self, nums):
p = 1
n = len(nums)
output = []
for i in range(n):
output.append(p)
p = p * nums[i]
p = 1
for i in range(n-1,-1,-1):
output[i] = output[i] * p
p = p * nums[i]
return output
239.滑动窗口最大值
遍历即可,时间复杂度是 O ( k n ) O(kn) O(kn)。
class Solution(object):
def maxSlidingWindow(self, nums, k):
if len(nums) == 0 or k == 0:
return []
result = []
for i in range(len(nums) - k+1):
result.append(max(nums[i:i+k]))
return result
240.搜索二维矩阵 II:
暴力法直接遍历:
class Solution(object):
def searchMatrix(self, matrix, target):
for i in range(len(matrix)):
for j in range(len(matrix[0])):
if matrix[i][j] == target:
return True
return False
矩阵是每行的元素从左到右升序排列。每列的元素从上到下升序排列。所以可以从右上到左下遍历,如果matrix[i][j]小于这个target,那么i加1,大于target则j减1。
class Solution(object):
# 76 ms 62.66%
# 15.7Mb
def searchMatrix(self, matrix, target):
if len(matrix) == 0 or len(matrix[0]) == 0:
return False
i,j = 0,len(matrix[0])-1
while i < len(matrix) and j >= 0:
if matrix[i][j] == target:
return True
elif matrix[i][j] < target:
i += 1
elif matrix[i][j] > target:
j -= 1
return False
264.丑数:
判断一个2,3,5是否是它的因子(通过取余来实现),如果是他的因子那么除以2,3,5。在num变成1之前,如果2,3,5均不是他的因子,那么不是丑数,如果最后得到1便是丑数。
class Solution(object):
def isUgly(self, num):
divids = [2,3,5]
while num != 1:
prev = num
for divid in divids:
if num%divid == 0:
num = num/divid
break
if num == prev:
return False
return True
同样的思路,判断是不是2,3,5的倍数,如果是的话就除以这个因子,但是代码明显更秀。
class Solution(object):
def isUgly(self, num):
if num == 0:
return False
while num%2 == 0:num /= 2
while num%3 == 0:num /= 3
while num%5 == 0:num /= 5
return num == 1
265.丑数II:
依次生成,将生成的丑数保存在ugly_set中,每次取最小的一个作为下一个丑数,然后将这个丑数在ugly_set去掉,result*2,3,5的每一个值依次保存在ugly_set中。
class Solution(object):
def nthUglyNumber(self, n):
if n == 0:
return 0
count = 1
ugly_set = set()
result = 1
while count < n:
ugly_set.add(result*2)
ugly_set.add(result*3)
ugly_set.add(result*5)
result = min(ugly_list)
count += 1
ugly_list.remove(result)
return result
284.移动零:
遍历遇到0就remove,然后在末尾添新的0。
class Solution(object):
def moveZeroes(self, nums):
for num in nums:
if num == 0:
nums.remove(0)
nums.append(0)
return nums
287.寻找重复数
排序,然后判断两个相邻的数是否相等,如果相等那么是重复的: O ( n l o g n ) O(nlogn) O(nlogn)。空间复杂度0.
class Solution:
def findDuplicate(self, nums):
nums.sort()
for i in range(1, len(nums)):
if nums[i] == nums[i-1]:
return nums[i]
哈希表保存次数: O ( n ) O(n) O(n),空间复杂度较高。
class Solution(object):
# 84ms 38.32%
# 14.9Mb 5.09%
def findDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
count = {}
for num in nums:
count[num] = count.get(num,0) + 1
for num in nums:
if count[num] > 1:
return num
return None
采用set保存已经出现过的数,比上一种更快。
def findDuplicate(self, nums):
seen = set()
for num in nums:
if num in seen:
return num
seen.add(num)
409.Longest Palindrome
统计字符串中每个字符的出现的次数,如果次数为偶数,直接相加,奇数除以2取整。count/2*2
# 28ms
# 11.6Mb
class Solution:
def longestPalindrome(self, s):
ans = 0
for v in collections.Counter(s).values():
ans += int(v / 2) * 2
if ans & 1 == 0 and v & 1 == 1:
ans += 1
return ans
438. 找到字符串中所有字母异位词
暴力做法,遍历所有字符串
class Solution(object):
def findAnagrams(self, s, p):
"""
:type s: str
:type p: str
:rtype: List[int]
"""
result = []
len_p = len(p)
for i in range(len(s)-len_p+1):
if sorted(s[i:i+len_p]) == sorted(p):
result.append(i)
return result
448.找到所有数组中消失的数字:
保存完整数组,然后遍历。
class Solution(object):
# 464 ms,73.91%
def findDisappearedNumbers(self, nums):
result = []
nums2 = list(range(1,len(nums)+1))
nums = set(nums)
return [num for num in nums2 if num not in nums]
461.汉明距离:
异或然后求其二进制中1的个数直接判断。
class Solution(object):
def hammingDistance(self, x, y):
result = x^y
count = 0
for i in str(bin(result)):
if i == '1':
count += 1
return count
494. 目标和
DFS
581.最短无序连续子数组:
对原数组进行排序,比较排好序的数组和原数组的差别,第一位不同的便是最短无序子数组的头;倒序遍历,第一个不同的便是尾。
class Solution(object):
# 264ms 32.54%
def findUnsortedSubarray(self, nums):
nums2 = sorted(nums)
for i in range(len(nums)):
if nums[i] != nums2[i]:
start = i
break
for i in range(len(nums)-1, -1,-1):
if nums[i] != nums2[i]:
end = i
break
try:
return end-start+1
except:
return 0
617.合并二叉树:
采用递归,将第二颗二叉树额值依次加到第一棵树上面,如果某一个棵树为None则返回另一颗树。确定根节点后,依次再向下考虑左右叶子结点。
class Solution(object):
# 84 ms # 59.6%
def mergeTrees(self, t1, t2):
if t1 == None:
return t2
if t2 == None:
return t1
t1.val += t2.val
t1.left = self.mergeTrees(t1.left, t2.left)
t1.right = self.mergeTrees(t1.right, t2.right)
return t1
647. Palindromic Substrings
暴力做法,确定每一个子字符串是否是回文字符串,然后统计个数
class Solution(object):
def countSubstrings(self, s):
"""
:type s: str
:rtype: int
"""
count = 0
def IsPalin(strs):
# 判断一个字符串是否是回文字符串,头和尾比较
for i in range(int(len(strs)/2)):
if strs[i] != strs[-i-1]:
return False
return True
def IsPalin2(strs):
# 判断是否是回文,翻转字符串判断是否相等
if strs[::-1] == strs:
return True
return False
for i in range(len(s)):
for j in range(i+1, len(s)+1):
if IsPalin(s[i:j]):
count += 1
return count
遍历字符串,以每个字符为中心,向两边展开,判断每个新加入的字母是否相等。
class Solution(object):
def countSubstrings(self, s):
"""
:type s: str
:rtype: int
"""
count = 0
for i in range(len(s)):
start,end = i,i
while(start >= 0 and end < len(s) and s[start] == s[end]):
start -= 1
end += 1
count += 1
start,end = i,i+1
while(start >= 0 and end < len(s) and s[start] == s[end]):
start -= 1
end += 1
count += 1
return count
771. Jewels and Stones
class Solution(object):
def numJewelsInStones(self, J, S):
"""
:type J: str
:type S: str
:rtype: int
"""
return sum([1 if i in J else 0 for i in S])