leetcode解题笔记--part1--array

目录


 11. Container With Most Water

 15. 3Sum

 16. 3Sum Closest

 18. 4Sum   ★★

 31. Next Permutation

 33. Search in Rotated Sorted Array    ★

 34. Search for a Range

 39. Combination Sum   ★★

 40. Combination Sum II

 48. Rotate Image

 54. Spiral Matrix

 55. Jump Game  ★★

 56. Merge Intervals

 59. Spiral Matrix II

 62. Unique Paths

 63. Unique Paths II

 64. Minimum Path Sum

 73. Set Matrix Zeroes  ★

 74. Search a 2D Matrix

 75. Sort Colors

 78. Subsets  ★★

 79. Word Search  ★

 80. Remove Duplicates from Sorted Array II

 81. Search in Rotated Sorted Array II  ★

 90. Subsets II

 105. Construct Binary Tree from Preorder and Inorder Traversal   ★★

 106. Construct Binary Tree from Inorder and Postorder Traversal

 120. Triangle

 152. Maximum Product Subarray  ★★

 153. Find Minimum in Rotated Sorted Array  ★

 162. Find Peak Element   ★

 209. Minimum Size Subarray Sum   ★★

 216. Combination Sum III

 228. Summary Ranges

 229. Majority Element II   ★★

 238. Product of Array Except Self ★

 287. Find the Duplicate Number  ★★

 289. Game of Life  ★★

 380. Insert Delete GetRandom O(1)   ★

 442. Find All Duplicates in an Array ★★

 495. Teemo Attacking

 560. Subarray Sum Equals K  ★

 565. Array Nesting

 611. Valid Triangle Number

 621. Task Scheduler  ★★

 667. Beautiful Arrangement II

 670. Maximum Swap ★

 713. Subarray Product Less Than K ★

 714. Best Time to Buy and Sell Stock with Transaction Fee ★★★

 718. Maximum Length of Repeated Subarray

 729. My Calendar I

 731. My Calendar II    ★


 

 

 

 

 

 

 

 


 11.Container With Most Water【Medium】    返回目录


 题目:

  

解题思路:  

没有叫你返回具体坐标,只要求最大面积的话,那么用一个变量记录下,然后两边开始往中间移动

对于长边来讲,往里边移动一个坐标,无论更长或者更短,都不会使面积变大,所以每次都移动短边,这样每移动一次,最大面积都有可能更新

Tip:如果不采用两边移动的话,就是要进行两两遍历,也就是O(n2), 两边移动就是O(n) 

 code:

 1 def maxArea(self, height):
 2         """
 3         :type height: List[int]
 4         :rtype: int
 5         """
 6         i = 0
 7         j = len(height)-1
 8         maxarea = 0
 9         while i < j:
10             maxarea = max((j-i)*min(height[i],height[j]), maxarea)
11             if height[i] < height[j]:
12                 i += 1
13             else:
14                 j -= 1
15         return maxarea

 

 

 

 

 

 


 

15. 3Sum【Medium】    返回目录


 题目:

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero

解题思路:

做2Sum的时候用的是hash算法O(N)就可以做完,那么这个3Sum其实就是一个O(N)的2Sum, 于是乎就是O(N*N)的算法

2Sum算法如下:O(N)

所以3Sum只需进行O(N)次2Sum就行了,写个循环完成

Tip:数组题要是涉及到找数字,记得用hash法,用空间换时间

code:

 1 def threeSum(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[List[int]]
 5         """
 6         length = len(nums)
 7         if length < 3:
 8             return []
 9         result = []
10         nums.sort()
11         for i in range(length-2):
12             if i>0 and nums[i]==nums[i-1]:
13                 continue
14             hash_table = {}
15             res = 0-nums[i] 
16             for j in range(i+1,len(nums)):
17                 if j>3 and nums[j]==nums[j-3]:
18                     continue
19                 if nums[j] in hash_table:
20                     result.append([nums[i],res-nums[j],nums[j]])
21                     hash_table.pop(nums[j])
22                 else:
23                     hash_table[res-nums[j]] = nums[j]
24         return result

 哇,这道题处理重复很头疼啊,对于[1,0,-1,1]结果为[[1,0,-1],[0,-1,1]]显示说答案错误

如果找到一组解的时候,在result里面查询是否已经存在的话就会多一层循环,结果会超时。

所以这里预先将数组进行排序,让可行的结果呈顺序状,更好地防止结果重复。

但是面对大量重复数字的时候,出现很多问题, 比如[0,0,0,0,0,0,0,0,0,0,0,0], [-4,2,2,2,2,2,2,2,3]

这里就要求固定第一个数字的时候,希望不重复,也就是要跳过nums[i]==nums[i-1]的情况

对于第二个数字呢,因为只要求2sum,所以对于重复大于3的情况不需要考虑。即跳过nums[j]==nums[j-3]

很奇怪为什么我的算法ac时间很长,统计数据只打败了2.9%提交的python代码,看下别人的解法

code_writen_by_others:

 1 def threeSum(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[List[int]]
 5         """
 6         length = len(nums)
 7         if length < 3:
 8             return []
 9         result = []
10         nums.sort()
11         for i in range(length-2):
12             if i>0 and nums[i]==nums[i-1]:
13                 continue
14             res = 0 - nums[i]
15             low = i+1
16             high = length-1
17             while(low < high):
18                 if(nums[low]+nums[high]==res):
19                     result.append([nums[i],nums[low],nums[high]])
20                     while(low<high and nums[low]==nums[low+1]):
21                         low += 1
22                     while(low<high and nums[high]==nums[high-1]):
23                         high -= 1
24                     low +=1
25                     high -=1
26                 else:
27                     if(nums[low]+nums[high]<res):
28                         low += 1
29                     else:
30                         high -= 1
31         return result

 

我好笨啊,因为已经排好序了,所以没必要用hash,直接两头做加法往中间移动,比hash省了空间还省了时间

但是2Sum用hash更好,因为排序算法是O(NlogN)的,hash是O(N)的,所以追求效率的话还是hash 

 

 

 

 


 

16. 3Sum Closest【Medium】     返回目录


 题目:

解题思路:

与15题类似,只不过需要一个额外的哨兵记录下与目标的差异,遍历完留下差异最小的值

同时在遍历的过程中,如果比target要更大,需要移动更大的数变小,如果比target更小,需要移动更小的数变大

Tips:如果算法的时间复杂度为O(N*N), 那么最好事先就先排序,排好序之后就没有必要hash了,本来两头遍历复杂度也为O(N)

code: 

 1 def threeSumClosest(self, nums, target):
 2         """
 3         :type nums: List[int]
 4         :type target: int
 5         :rtype: int
 6         """
 7         nums.sort()
 8         min_diff = float("inf")
 9         for i in range(len(nums)):
10             res = target-nums[i]
11             low,high = i+1,len(nums)-1
12             while low < high:
13                 diff = nums[low]+nums[high]-res
14                 if diff == 0:
15                     return target
16                 if abs(diff) < min_diff:
17                     min_diff = abs(diff)
18                     result = nums[i]+nums[low]+nums[high]
19                 if diff > 0:
20                     high -= 1
21                 else:
22                     low += 1
23         return result   

 

 

 

 


 18. 4Sum【Medium】    返回目录


 

题目:

解题思路:

在网上看了一个特别brilliant的解法,让人觉得代码很有美感,而且还非常高效,就是把所有不需要的测试全部略过,让人赞叹不已

而且这道题还结合了前几道题的操作,这道题必须mark上两颗星

Tips:去除一些不必要的操作,虽然时间复杂度没有变,但是实际运行时间是减少的

code:

 1 def fourSum(self, nums, target):
 2         """
 3         :type nums: List[int]
 4         :type target: int
 5         :rtype: List[List[int]]
 6         """
 7         nums.sort()
 8         res = []
 9         if len(nums)<4 or 4*nums[0]>target or 4*nums[-1]<target:
10             return res
11         for i in range(len(nums)):
12             if i>0 and nums[i]==nums[i-1]:
13                 continue
14             if nums[i] + 3*nums[-1] < target:
15                 continue
16             if 4*nums[i] > target:
17                 break
18             if 4*nums[i] == target:
19                 if i+3<len(nums) and nums[i+3]==nums[i]:
20                     res.append([nums[i],nums[i],nums[i],nums[i]])
21                 break
22             res.extend(self.threeSum(nums[i+1:],target-nums[i],nums[i]))
23         return res
24     
25     def threeSum(self,nums,target,a):
26         res = []
27         if len(nums)<3 or 3*nums[0]>target or 3*nums[-1]<target:
28             return res
29         for i in range(len(nums)):
30             if i>0 and nums[i]==nums[i-1]:
31                 continue
32             if nums[i] + 2*nums[-1] < target:
33                 continue
34             if 3*nums[i] > target:
35                 break
36             if 3*nums[i] == target:
37                 if i+2<len(nums) and nums[i+2] == nums[i]:
38                     res.append([a,nums[i],nums[i],nums[i]])
39                 break
40             res.extend(self.twoSum(nums[i+1:],target-nums[i],a,nums[i]))
41         return res
42     
43     def twoSum(self,nums,target,a,b):
44         res = []
45         if len(nums)<2 or 2*nums[0]>target or 2*nums[-1]<target:
46             return res
47         i,j = 0,len(nums)-1
48         while i<j:
49             sum_temp = nums[i]+nums[j]
50             if sum_temp == target:
51                 res.append([a,b,nums[i],nums[j]])
52                 i += 1
53                 j -= 1
54             elif sum_temp > target:
55                 j -= 1
56             else:
57                 i += 1
58             while i>0 and i<len(nums) and nums[i]==nums[i-1]:
59                 i += 1
60             while j>0 and j<len(nums)-1 and nums[j]==nums[j+1]:
61                 j -= 1
62         return res

 

 

 

 


31. Next Permutation【Medium】   返回目录


 

题目:

给你一个排列,要你求出,作为全排列组合中它的下一个排列。一般都是指一个升序数列的全排列An^n个,比如说:

[1,2,3] --> [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] --> [1,2,3]

本题要求:找到给出排列的下一个排列  

解题思路:

观察找到全排列的规律,发现是个多重循环,按位置从小到大,可以得到的规律如下:【借鉴别人给出的例子,侵删】

1 2 7 4 3 1   -->    1 3 1 2 4 7 

从末尾往前看,数字逐渐变大,找到第一个开始变小的数字,也就是2

1 2 7 4 3 1         然后从后面往前找到第一个大于2的数字,也就是3,这里是想说第二个位置2后面的已经全排列完了,可以换成3了

1 3 7 4 2 1   换成三后面的又要重新进行全排列,全排列最后一个是逆序,第一个是顺序,所以只需要将3后面的翻转一下就可以

1 3 1 2 4 7

code:

 1 def nextPermutation(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: void Do not return anything, modify nums in-place instead.
 5         """
 6         a = -1
 7         for i in range(len(nums)-1,0,-1):
 8             if nums[i] > nums[i-1]:
 9                 a = i-1
10                 break
11         if a==-1:
12             return nums.reverse()
13         b = a+1
14         for j in range(len(nums)-1,a,-1):
15             if nums[j]>nums[a]:
16                 b = j
17                 break
18         nums[a],nums[b] = nums[b],nums[a]
19         i,j = a+1,len(nums)-1
20         while i<j:
21             nums[i],nums[j] = nums[j],nums[i]
22             i += 1
23             j -= 1

 

 


 

33. Search in Rotated Sorted Array【Medium】   返回目录


 

题目:

就是说给定的数组是由一个升序数组就某个点翻转得到的,然后要在这样一个数组中查找某个数字,返回下标

 

解题思路:

直接暴力搜索,O(N)  我以为会超时,结果Accepted    可以没有利用到给定数组的特性,如果是升序数组的话可以用二分法是O(logN), 所以可以设计一个改进版二分法来处理这个问题

分两种情况:

a)mid如果在左边 :  target在mid左  high=mid-1    target在mid右  low=mid+1

b)mid如果在右边 :   target在mid左  high=mid-1    target在mid右  low=mid+1

 

code:(暴力法)     beat  16.87%

 1 def search(self, nums, target):
 2         """
 3         :type nums: List[int]
 4         :type target: int
 5         :rtype: int
 6         """
 7         for i in range(len(nums)):
 8             if nums[i] == target:
 9                 return i
10         return -1

 

code:(改进二分法)     beat 25.32%

 1 def search(self, nums, target):
 2         """
 3         :type nums: List[int]
 4         :type target: int
 5         :rtype: int
 6         """
 7         if len(nums) < 1:
 8             return -1
 9         low,high = 0, len(nums)-1
10         while(low<high):
11             mid = (low + high) // 2 
12             if nums[mid] == target:
13                 return mid
14             if nums[low] <= nums[mid]:
15                 if target >= nums[low] and target < nums[mid]:
16                     high = mid - 1
17                 else:
18                     low = mid + 1
19             else:
20                 if target > nums[mid] and target <= nums[high]:
21                     low = mid + 1
22                 else:
23                     high = mid -1
24         if nums[low] == target:
25             return low
26         else:
27             return -1

 

 

 

 


34. Search for a Range 【Medium】    返回目录


 

题目:

 

解题思路:

要求在O(logn)时间内,那么就是希望我们用二分法进行查找,首先先用二分法找到相应的值,然后再向左判断边界,再向右判断边界,向左向右的过程中都是使用二分法

 

code:  beat 21.43%

 

 1 def searchRange(self, nums, target):
 2         """
 3         :type nums: List[int]
 4         :type target: int
 5         :rtype: List[int]
 6         """
 7         if len(nums) < 1:
 8             return [-1,-1]
 9         low,high = 0,len(nums)-1
10         if nums[0]>target or nums[-1]<target:
11             return [-1,-1]
12         while(low <= high):
13             mid = (low+high)//2
14             if nums[mid] < target:
15                 low = mid + 1
16             elif nums[mid] == target: 
17                 b = mid
18                 high = mid - 1
19             else:
20                 high = mid - 1
21         if nums[high+1] != target:
22             return [-1,-1]
23         a = high+1
24         high = len(nums)-1
25         while(low <= high):
26             mid = (low+high)//2
27             if nums[mid] > target:
28                 high = mid - 1
29             else:
30                 low = mid + 1
31         return [a,low-1]

 

 

 

 


 

39. Combination Sum 【Medium】  返回目录


 

题目:

 

解题思路:

搜索+回溯  这道题很经典,理清楚怎么递归和回溯很重要

主要思路就是先第一个数字,再递归的求target-第一个数字,可以的话继续递归,不可以就回溯

我发现我真是有点笨,经常想不通怎么回溯

dfs的算法一定要非常熟悉,在python中通常都是要把path和result作为参数传入dfs函数中,用以记录可行的结果

 

Tips:求所有可能的解的时候就要想到搜索和递归

 

code:    参考的别人写的代码     beat 69.7% (大神就是厉害)

 1   def combinationSum(self, candidates, target):
 2         """
 3         :type candidates: List[int]
 4         :type target: int
 5         :rtype: List[List[int]]                             
 6         """
 7         res = []
 8         self.dfs(candidates,target,0,[],res)
 9         return res
10     def dfs(self,nums,target,index,path,res):
11         if target<0:
12             return 
13         elif target==0:
14             res.append(path)
15             return
16         else:
17             for i in range(index,len(nums)):
18                 self.dfs(nums,target-nums[i],i,path+[nums[i]],res)

 

 

上面的是递归回溯,下面是栈回溯

code:   beat 68.18%

 1 def combinationSum(self, candidates, target):
 2         """
 3         :type candidates: List[int]
 4         :type target: int
 5         :rtype: List[List[int]]                             
 6         """
 7         res = []
 8         self.dfs(candidates,target,0,[],res)
 9         return res
10     def dfs(self,nums,target,index,path,res):
11         if target<0:
12             return 
13         elif target==0:
14             res.append(path[:])
15             return
16         else:
17             for i in range(index,len(nums)):
18                 path.append(nums[i])
19                 self.dfs(nums,target-nums[i],i,path,res)
20                 path.pop()

 

而且我今天还对python中的赋值机制进行了深入的学习,起因是第14行代码 如果直接写成 res.append(path)的话,后面修改path是在原地址上修改,起不到保存结果的作用,所以用path[:]切片操作,相当于创建了一个新的对象进行保存,就可以让代码正常运行了

学习链接是: https://my.oschina.net/leejun2005/blog/145911  这个博客解释得相当清楚

 

 


40. Combination Sum II 【Medium】  返回目录


 

 

题目:  同39  只是要求一个数只能用一次,所以只是循环的时候要求index+1,具体细节看39题

code:   beat 73.81%

 1   def combinationSum2(self, candidates, target):
 2         """
 3         :type candidates: List[int]
 4         :type target: int
 5         :rtype: List[List[int]]
 6         """
 7         res = []
 8         candidates.sort()
 9         print(candidates)
10         self.dfs(candidates,target,[],0,res)
11         return res
12     def dfs(self,nums,target,path,index,res):
13         if target<0:
14             return
15         elif target==0:
16             res.append(path)
17             return
18         else:
19             for i in range(index,len(nums)):
20                 if i>index and nums[i]==nums[i-1]:
21                     continue
22                 self.dfs(nums,target-nums[i],path+[nums[i]],i+1,res)

 

 

 


 

48. Rotate Image 【Medium】   返回目录


 

题目:

 

解题思路:

主要是寻找旋转前和旋转后坐标位置的对应关系,我们发现 

      

所以就是对每一个正方形框的上边进行逐个元素的旋转置位,就可以了

 

code:  beat 70.69%  完全自己写的,好有成就感哈哈哈~

1 def rotate(self, matrix):
2         """
3         :type matrix: List[List[int]]
4         :rtype: void Do not return anything, modify matrix in-place instead.
5         """
6         n = len(matrix)-1
7         for i in range(n//2+1):
8             for j in range(n-2*i):
9                 matrix[i][i+j],matrix[i+j][n-i],matrix[n-i][n-i-j],matrix[n-i-j][i] = matrix[n-i-j][i],matrix[i][i+j],matrix[i+j][n-i],matrix[n-i][n-i-j]

 

 

 然后看了下别人的解法

code:     比我的解法简单太多了,膜拜大神

 1 def rotate(self, matrix):
 2         """
 3         :type matrix: List[List[int]]
 4         :rtype: void Do not return anything, modify matrix in-place instead.
 5         """
 6         '''
 7         clockwise rotate
 8         first reverse up to down, then swap the symmetry 
 9         1 2 3     7 8 9     7 4 1
10         4 5 6  => 4 5 6  => 8 5 2
11         7 8 9     1 2 3     9 6 3
12         '''
13         matrix.reverse()
14         n = len(matrix)
15         for i in range(n-1):
16             for j in range(i+1,n):
17                 matrix[i][j],matrix[j][i] = matrix[j][i],matrix[i][j]

 

 

 


54. Spiral Matrix【Medium】   返回目录


 

题目:把矩阵螺旋展开,不一定是方阵

 

解题思路:

每个回路都对四条边进行遍历,坐标规律自己找,就是需要考虑好多情况,代码时完全debug出来的

 

code:  beat 87%

 1 def spiralOrder(self, matrix):
 2         """
 3         :type matrix: List[List[int]]
 4         :rtype: List[int]
 5         """
 6         res = []
 7         if not len(matrix):
 8             return []
 9         h,w = len(matrix),len(matrix[0])
10         if not w:
11             return []
12         n = (min(h,w)-1)//2
13         for i in range(n+1):
14             for j in range(w):
15                 res.append(matrix[i][i+j])
16             if h-1:
17                 for j in range(1,h):
18                     res.append(matrix[i+j][i+w-1])
19             if h-1 and w-1:
20                 for j in range(1,w):
21                     res.append(matrix[i+h-1][i+w-j-1])
22             if w-1 and h-1:
23                 for j in range(1,h-1):
24                     res.append(matrix[i+h-j-1][i])
25             h -= 2
26             w -= 2
27         return res

 

参考别人的代码,我发现我想的太过于复杂或者说细节要考虑的太多,导致需要大量时间调试,舍本求末,其实很简单,只需要colbegin<=colend and rowbegin<=rowend这一个限制条件就可以了,没必要对所有的坐标特点都清楚

Tips:如果对于矩阵中的遍历,清楚地知道begin and end那么就没有必要知道i,j的变化细节

 

code:

 1 def spiralOrder(self, matrix):
 2         """
 3         :type matrix: List[List[int]]
 4         :rtype: List[int]
 5         """
 6         if not len(matrix):
 7             return []
 8         if not len(matrix[0]):
 9             return []
10         res = []
11         rowbegin,rowend = 0,len(matrix)-1
12         colbegin,colend = 0,len(matrix[0])-1
13         while(rowbegin<=rowend and colbegin<=colend):
14             for j in range(colbegin,colend+1):
15                 res.append(matrix[rowbegin][j])
16             rowbegin += 1
17             for j in range(rowbegin,rowend+1):
18                 res.append(matrix[j][colend])
19             colend -= 1
20             if rowbegin<=rowend: 
21                 for j in range(colend,colbegin-1,-1):
22                     res.append(matrix[rowend][j])
23             rowend -=1
24             if colbegin<=colend:
25                 for j in range(rowend,rowbegin-1,-1):
26                     res.append(matrix[j][colbegin])
27             colbegin += 1
28         return res      

 

 注意,当遍历到下边和左边的时候,要进行判断,是否满足还可以遍历的条件

 

 


55. Jump Game 【Medium】   返回目录


 

题目:

 

 

解题思路:

我看到这个题目,第一眼就想到用递归深搜去做,结果直接超时,因为这个分支太多,用dfs适合那种分支较少的题目,比如说 39 ,像这种比较多情况的容易重复计算的题目就适合用动态规划做,这样就可以节省时间 

动态规划的题最大的点就是要找到最优子结构:

for i in range(1,nums[i]):

  dp[index] += dp[i]

如果用递归的话,dp[i]要被反复计算, 用动态规划的话,dp[i]只需要计算一次然后记录下来,整个过程应该是倒着来的

 

Tips:如果发现递归会有很多重复的求解,那么就改成动态规划

 

code:

我的超时解法:

 1 def canJump(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: bool
 5         """
 6         dp = nums[:]
 7         dp[len(nums)-1] = True
 8         for i in range(len(nums)-2,-1,-1):
 9             dp[i] = False
10             for j in range(i+1,i+nums[i]+1):
11                 if dp[j]:
12                     dp[i] = True
13                     break
14         return dp[0]

 

 

 然后看别人的解法,发现,没有必要对每个点可以到达的地方都进行遍历,只需要对最大能到达的地方进行记录,当最大能到达的地方大于终点说明就能到达终点

 

code:

 1 def canJump(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: bool
 5         """
 6         i = 0
 7         reach = 0
 8         for i in range(len(nums)):
 9             if i>reach:
10                 break
11             reach = max(i+nums[i],reach)
12         return reach>=len(nums)-1

 

 

 

 


 

56. Merge Intervals【Medium】   返回目录


 

题目:

 

解题思路:

本来想用初中学的数轴法,也就是用一个flag记录是否需要覆盖,可是发现数轴法不适用,所以还是先排序,再遍历吧

 

code:     数轴法[wrong error]

 1 # Definition for an interval.
 2 # class Interval:
 3 #     def __init__(self, s=0, e=0):
 4 #         self.start = s
 5 #         self.end = e
 6 
 7 class Solution:
 8     def merge(self, intervals):
 9         """
10         :type intervals: List[Interval]
11         :rtype: List[Interval]
12         """
13         flag = []
14         for i in range(len(intervals)):
15             for j in range(len(flag),intervals[i].start):
16                 flag.append(0)
17             end = min(intervals[i].end+1,len(flag))
18             for j in range(intervals[i].start,end):
19                 flag[j] = 1
20             for j in range(end,intervals[i].end+1):
21                 flag.append(1)
22         res = []
23         i = 0 
24         while i<len(flag):
25             if flag[i]:
26                 temp = Interval(s=i)
27                 while i<len(flag) and flag[i]:
28                     i += 1
29                 temp.end = i-1
30                 res.append(temp)
31             else:
32                 i += 1
33         return res
34         

 

 

code:  Accepted

 1 # Definition for an interval.
 2 # class Interval:
 3 #     def __init__(self, s=0, e=0):
 4 #         self.start = s
 5 #         self.end = e
 6 
 7 class Solution:
 8     def merge(self, intervals):
 9         """
10         :type intervals: List[Interval]
11         :rtype: List[Interval]
12         """
13         if not intervals:
14             return []
15         intervals.sort(key=self.getKey)
16         temp = intervals[0]
17         res = []
18         for i in range(1,len(intervals)):
19             if intervals[i].start<=temp.end:
20                 temp.end = max(intervals[i].end,temp.end)
21             else:
22                 res.append(temp)
23                 temp = intervals[i]
24         res.append(temp)
25         return res
26     
27     def getKey(self, interval):
28         return interval.start

 学会了结构体排序的方法   sorted(intervals, key=lambda i: i.start)     list.sort(intervals, key=lambda i: i.start)  或者写成显示的函数

 

 


59. Spiral Matrix II 【Medium】   返回目录


题目:

 

解题思路:

54 题, 使用的是第二种解法

 

code:

 1 def generateMatrix(self, n):
 2         """
 3         :type n: int
 4         :rtype: List[List[int]]
 5         """
 6         rowbegin = colbegin = 0
 7         rowend = colend = n-1
 8         res = [ [ 0 for i in range(n) ] for j in range(n) ]
 9         count = 1
10         while rowbegin <= rowend and colbegin <= colend:
11             for i in range(colbegin,colend+1):
12                 res[rowbegin][i] = count
13                 count += 1
14             rowbegin += 1
15             for i in range(rowbegin,rowend+1):
16                 res[i][colend] = count
17                 count += 1
18             colend -= 1
19             if rowbegin<=rowend:
20                 for i in range(colend,colbegin-1,-1):
21                     res[rowend][i] = count
22                     count += 1
23             rowend -= 1
24             if colbegin<=colend:
25                 for i in range(rowend,rowbegin-1,-1):
26                     res[i][colbegin] = count
27                     count += 1
28             colbegin += 1
29         return res

 

 

 


 

62. Unique Paths 【Medium】    返回目录


 

题目:

 

解题思路:

因为有很多子路是重复的,所以用动态规划比较好,最优子结构是 dp[i][j] = dp[i-1][j] + dp[i][j+1]    然后从目的地开始倒着填这张动态规划表就可以,倒着从行开始,再倒着列

 

code:   第一次写完代码一遍过,开心,决定再写一道

 1 def uniquePaths(self, m, n):
 2         """
 3         :type m: int
 4         :type n: int
 5         :rtype: int
 6         """
 7         dp = [[1 for i in range(n)] for j in range(m)]
 8         for i in range(m-2,-1,-1):
 9             for j in range(n-2,-1,-1):
10                 dp[i][j] = dp[i+1][j] + dp[i][j+1]
11         return dp[0][0]

对算法进行优化,时间复杂度变不了了O(mn), 看答案发现空间复杂度可以进行优化成O(min(m,n)), 可以只留下一行空间:

code:

 1 def uniquePaths(self, m, n):
 2         """
 3         :type m: int
 4         :type n: int
 5         :rtype: int
 6         """
 7         if m > n: 
 8             return self.uniquePaths(n, m)
 9         dp = [1 for i in range(m)]
10         for j in range(1,n):
11             for i in range(1,m):
12                 dp[i] += dp[i-1]
13         return dp[m-1]

 

 

 

 

 


63. Unique Paths II 【Medium】   返回目录


 

 题目:

 

 

解题思路:

和上面一题一样,只不过多加了个障碍物,做法一样,倒着填dp表,只不过需要些限制条件,如果位置为1的话,那么计算的时候不能把它算在里面

首先要将0,1反过来,用0表示障碍物会方便计算

 

code:

 1 def uniquePathsWithObstacles(self, obstacleGrid):
 2         """
 3         :type obstacleGrid: List[List[int]]
 4         :rtype: int
 5         """
 6         m = len(obstacleGrid)
 7         if not m:
 8             return 0
 9         n = len(obstacleGrid[0])
10         if obstacleGrid[m-1][n-1] or obstacleGrid[0][0]:
11             return 0
12         dp = [[1-obstacleGrid[i][j] for j in range(n)] for i in range(m)]
13         for i in range(m-2,-1,-1):
14             dp[i][n-1] = dp[i+1][n-1] & dp[i][n-1]
15         for j in range(n-2,-1,-1):
16             dp[m-1][j] = dp[m-1][j+1] & dp[m-1][j]
17         for i in range(m-2,-1,-1):
18             for j in range(n-2,-1,-1):
19                 print(i,j)
20                 if dp[i][j]:
21                     dp[i][j] = dp[i+1][j] + dp[i][j+1]
22         return dp[0][0]

 

 

 

 


64. Minimum Path Sum 【Medium】   返回目录


 

题目:

 

 

解题思路:

和前面两题一样,用动态规划做  dp[i][j] = min(dp[i+1][j],dp[i][j+1])+matrix[i][j]

 

code:   感觉现在自己做这种题都能一遍过呀,厉害厉害,鼓掌~

 1 def minPathSum(self, grid):
 2         """
 3         :type grid: List[List[int]]
 4         :rtype: int
 5         """
 6         m = len(grid)
 7         if not m:
 8             return 0
 9         n = len(grid[0])
10         for i in range(m-2,-1,-1):
11             grid[i][n-1] = grid[i][n-1] + grid[i+1][n-1]
12         for j in range(n-2,-1,-1):
13             grid[m-1][j] = grid[m-1][j] + grid[m-1][j+1]
14         for i in range(m-2,-1,-1):
15             for j in range(n-2,-1,-1):
16                 grid[i][j] = min(grid[i+1][j],grid[i][j+1])+grid[i][j]
17         return grid[0][0]

 

 

 

 


 

73. Set Matrix Zeroes 【Medium】   返回目录


 

题目:

 

 

解题思路:

这道题看起来好像很容易,但是注意要求in place也就是不能用额外的空间,主要问题是当你处理遇到的第一个0的时候,你把当行当列都置为0,那么其他0的位置信息就被覆盖了,所以需要额外的空间存储之前0的位置信息,但是要求in place

所以就需要高效利用本身的空间,并且不冲掉已有信息,所以这里用每行的第一个位置记录每行的状态,每列的第一个位置记录每列的状态,因为row0 col0的位置重合了,所以需要额外的一个空间 O(1)算法

 

 

code:  这道题折腾了一下,想叉了,参考别人做法的

 1 def setZeroes(self, matrix):
 2         """
 3         :type matrix: List[List[int]]
 4         :rtype: void Do not return anything, modify matrix in-place instead.
 5         """
 6         m = len(matrix)
 7         if not m:
 8             return
 9         n = len(matrix[0])
10         col0 = 1
11         for i in range(m):
12             for j in range(n):
13                 if not matrix[i][j]:
14                     if not j:
15                         col0 = 0
16                     else:
17                         matrix[0][j] = 0
18                     matrix[i][0] = 0
19         for i in range(1,m):
20             for j in range(1,n):
21                 if matrix[i][0]==0 or matrix[0][j]==0:
22                     matrix[i][j] = 0
23         if not matrix[0][0]:
24             for j in range(1,n):
25                 matrix[0][j] = 0
26         if not col0:
27             for i in range(m):
28                 matrix[i][0] = 0

 

 

 

 

 


74. Search a 2D Matrix 【Medium】    返回目录


 

 题目:

 

解题思路:

感觉这道题很简单,先按行使用二分法,确定target具体在哪一行,然后对于确定的行再用二分法,确定具体的列index

 

code:

 1 def searchMatrix(self, matrix, target):
 2         """
 3         :type matrix: List[List[int]]
 4         :type target: int
 5         :rtype: bool
 6         """
 7         rowbegin = 0
 8         rowend = len(matrix)-1
 9         if rowend<0:
10             return False
11         colbegin = 0
12         colend = len(matrix[0])-1
13         if colend < 0:
14             return False
15         res = False
16         while rowbegin<=rowend:
17             midrow = (rowbegin+rowend)//2
18             if matrix[midrow][colbegin] <= target <= matrix[midrow][colend]:
19                 while colbegin<=colend:
20                     midcol = (colbegin+colend)//2
21                     if matrix[midrow][midcol]==target:
22                         res = True
23                         return res
24                     elif matrix[midrow][midcol]<target:
25                         colbegin = midcol + 1
26                     else:
27                         colend = midcol - 1
28                 return res
29             elif target > matrix[midrow][colend]:
30                 rowbegin = midrow + 1
31             elif target < matrix[midrow][colbegin]:
32                 rowend = midrow - 1
33         return res

 

code: 我的解法有点啰嗦,看了别人的解法,简洁才是美,  不要把它看成是一个二维数组,应该把它当做是一个一维数组直接使用二分法进行查找

 1 def searchMatrix(self, matrix, target):
 2         """
 3         :type matrix: List[List[int]]
 4         :type target: int
 5         :rtype: bool
 6         """
 7         m = len(matrix)
 8         if not m:
 9             return False
10         n = len(matrix[0])
11         l, r = 0, m*n-1
12         while l <= r:
13             mid = (l+r) // 2
14             if matrix[mid//n][mid%n] == target:
15                 return True
16             elif matrix[mid//n][mid%n] < target:
17                 l = mid + 1
18             else:
19                 r = mid -1
20         return False

 

 


75. Sort Colors 【Medium】   返回目录


 

题目:

 

解题思路:

题目意思不是很好懂,就是说一个数组中有一堆0,1,2要你给排好序,相同数组排在一起,直接用nums.sort() 确实可以Accepted,但是因为是O(nlogn),所以时间很慢,提示要求只遍历一遍而且使用常数空间

我想的是用两个变量记录下1和2的开始的index,遇到相应的0,1就直接交换

 

code: 

 1 def sortColors(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: void Do not return anything, modify nums in-place instead.
 5         """
 6         one = 0
 7         two = 0
 8         for i in range(len(nums)):
 9             if nums[i] == 0:
10                 if i>=one:
11                     nums[i],nums[one] = nums[one],nums[i]
12                     one += 1
13                     if two < one:
14                         two = one
15             if nums[i] == 1:
16                 if i>=two:
17                     nums[i],nums[two] = nums[two],nums[i]
18                     two += 1

 

 

 

 

 

 


78. Subsets【Medium】  返回目录


 

题目:

 

解题思路:

递归求解,res做为参数传递

 

code:

 1 def subsets(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[List[int]]
 5         """
 6         res = []
 7         self.findset(res,0,[],nums)
 8         return res
 9     def findset(self,res,index,path,nums):
10         res.append(path)
11         for i in range(index,len(nums)):
12             self.findset(res,i+1,path+[nums[i]],nums)    #这里注意不要把i+1写成了index+1导致报错

 

 

看了下其他的参考答案,觉得真的很精妙啊,有用位运算的,也有迭代算法,位运算是非常切合子集运算这个任务了

 

code:  位运算

 1 def subsets(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[List[int]]
 5         """
 6         res = []
 7         for i in range(1<<len(nums)):
 8             tmp = []
 9             for j in range(len(nums)):
10                 if i & 1<<j:   #if i>>j & 1    看第j位是否为1,如果是就要加入到当前子集中
11                     tmp.append(nums[j])
12             res.append(tmp)
13         return res

 

 

code:  迭代算法

1 def subsets(self, nums):
2         """
3         :type nums: List[int]
4         :rtype: List[List[int]]
5         """
6         res = [[]]
7         for num in nums:
8             res += [item+[num] for item in res]
9         return res

 

 

 

 

 

 


79. Word Search【Medium】   返回目录


 题目:

 

解题思路:

先通过二层循环找到第一个字符,然后再展开dfs,自己按死方法写了个代码,超时了,注意,每一个位置只能visit一次

 

code:  超时算法

 1 def exist(self, board, word):
 2         """
 3         :type board: List[List[str]]
 4         :type word: str
 5         :rtype: bool
 6         """
 7         m = len(board)
 8         if not m or not word:
 9             return False
10         n = len(board[0])
11         if not n:
12             return False
13         for i in range(m):
14             for j in range(n):
15                 visit = [[0 for j in range(n)] for i in range(m)]
16                 if board[i][j] == word[0]:
17                     visit[i][j] = 1
18                     if self.neiborfind(i,j,word,1,board,visit):
19                         return True
20         return False
21     def neiborfind(self,i,j,word,index,board,visit):
22         if index==len(word):
23             return True
24         if i>0 and word[index]==board[i-1][j] and not visit[i-1][j]:
25             visit[i-1][j] = 1
26             if self.neiborfind(i-1,j,word,index+1,board,visit):
27                 return True
28             visit[i-1][j] = 0
29         if j>0 and word[index]==board[i][j-1] and not visit[i][j-1]:
30             visit[i][j-1] = 1
31             if self.neiborfind(i,j-1,word,index+1,board,visit):
32                 return True
33             visit[i][j-1] = 0
34         if i<len(board)-1 and word[index]==board[i+1][j] and not visit[i+1][j]:
35             visit[i+1][j] = 1
36             if self.neiborfind(i+1,j,word,index+1,board,visit):
37                 return True
38             visit[i+1][j] = 0
39         if j<len(board[0])-1 and word[index]==board[i][j+1] and not visit[i][j+1]:
40             visit[i][j+1] = 1
41             if self.neiborfind(i,j+1,word,index+1,board,visit):
42                 return True
43             visit[i][j+1] = 0
44         return False

 

code: Accepted 算法, 参考别人的, 发现原理和我自己写的几乎一样,就是写法高超了很多,膜拜膜拜

 1 def exist(self, board, word):
 2         if not board:
 3             return False
 4         for i in range(len(board)):
 5             for j in range(len(board[0])):
 6                 if self.dfs(board, i, j, word):
 7                     return True
 8         return False
 9  
10     def dfs(self, board, i, j, word):
11         if len(word) == 0:
12             return True
13         if i<0 or i>=len(board) or j<0 or j>=len(board[0]) or word[0]!=board[i][j]:
14             return False
15         tmp = board[i][j] 
16         board[i][j] = "#" 
17         res = self.dfs(board, i+1, j, word[1:]) or self.dfs(board, i-1, j, word[1:]) \
18         or self.dfs(board, i, j+1, word[1:]) or self.dfs(board, i, j-1, word[1:])
19         board[i][j] = tmp
20         return res

 

 

 

 

 

 

 


80. Remove Duplicates from Sorted Array II 【Medium】  返回目录


 

题目:

 

 解题思路:

就简单遍历吧

 

code:

 1 def removeDuplicates(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         i = 0
 7         while i < len(nums):
 8             if i>0 and nums[i]==nums[i-1]:
 9                 j = i+1
10                 while j<len(nums) and nums[j]==nums[i]:
11                     nums.pop(j)
12             i += 1
13         return len(nums)

 

 

我的解法还是不够简洁,其实没有必要pop的,参考别人的算法(主要利用了题目的条件,数组是已经升序排列好的,并且It doesn't matter what you leave beyond the new length)

code:

 1 def removeDuplicates(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         i = 0
 7         for num in nums:
 8             if i<2 or num>nums[i-2]:
 9                 nums[i] = num     #注意题目要求nums[:i+1]是剔除后的结果
10                 i += 1
11         return i

 

 

 

 

 

 

 


 

 81. Search in Rotated Sorted Array II 【Medium】   返回目录


 

题目:

 

解题思路: 

33 题中包含duplicates的情况,这样呢,就不方便事先判断mid是在左边还是在右边,如下面的情况

然后呢,就在判断左右边的情况下增加一种新的情况,就是当nums[mid] == nums[l], 那么就l++, 这样就可以转换成普通的情况了

比如上面,就转换成 [3,1,1,1]

 

code:

 1 def search(self, nums, target):
 2         """
 3         :type nums: List[int]
 4         :type target: int
 5         :rtype: bool
 6         """
 7         l,r = 0,len(nums)-1
 8         while l<=r:
 9             mid = (l+r)//2
10             print(l,r,mid)
11             if nums[mid] == target:
12                 return True
13             if nums[mid] > nums[l]:  # left
14                 if target>=nums[l] and target<nums[mid]:
15                     r = mid -1
16                 else:
17                     l = mid + 1
18             elif nums[mid] < nums[l]:                     # right
19                 if nums[mid]<target<=nums[r]:
20                     l = mid + 1
21                 else:
22                     r = mid - 1
23             else:
24                 l = l + 1
25         return False

 

 

 

 

 

 

 


90. Subsets II 【Medium】   返回目录


题目:

 解题思路:

类似于78 subset, 但是在找到一个答案要加入到最终结果list时,进行判断是否已经存在

因为使用了if tmp not in res:  res+=[tmp]   但是在list中[1,4]和[4,1]不是相同的,所以要事先进行排序,nums.sort()

code:

 1 def subsetsWithDup(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[List[int]]
 5         """
 6         nums.sort()
 7         res = [[]]
 8         for num in nums:
 9             res += [n+[num] for n in res if n+[num] not in res]
10         return res

 

用位操作或者dfs也是相同地进行判断操作就行

 

 

 

 

 

 

 

             

 


105. Construct Binary Tree from Preorder and Inorder Traversal 【Medium】   返回目录


 

题目:

 

 给前向遍历和中序遍历的序列,要求构建唯一的二叉树

 

解题思路:

   

可以利用inorder找到对preorder的左右子树的划分

 

code:   参考答案的   解法真是精妙绝伦

 1 # Definition for a binary tree node.
 2 # class TreeNode:
 3 #     def __init__(self, x):
 4 #         self.val = x
 5 #         self.left = None
 6 #         self.right = None
 7 
 8 class Solution:
 9     def buildTree(self, preorder, inorder):
10         """
11         :type preorder: List[int]
12         :type inorder: List[int]
13         :rtype: TreeNode
14         """
15         if inorder:
16             ind = inorder.index(preorder.pop(0))
17             root = TreeNode(inorder[ind])
18             root.left = self.buildTree(preorder,inorder[0:ind])
19             root.right = self.buildTree(preorder,inorder[ind+1:])
20             return root

 

 

 

 

 


106. Construct Binary Tree from Inorder and Postorder Traversal 【Medium】    返回目录


 

题目:

 

 

解题思路:

同上面那题,只不过顺序是倒着的

 

 

code:

 1 # Definition for a binary tree node.
 2 # class TreeNode:
 3 #     def __init__(self, x):
 4 #         self.val = x
 5 #         self.left = None
 6 #         self.right = None
 7 
 8 class Solution:
 9     def buildTree(self, inorder, postorder):
10         """
11         :type inorder: List[int]
12         :type postorder: List[int]
13         :rtype: TreeNode
14         """
15         if inorder:
16             ind = inorder.index(postorder.pop())
17             root = TreeNode(inorder[ind])
18             root.right = self.buildTree(inorder[ind+1:],postorder)
19             root.left = self.buildTree(inorder[0:ind],postorder)
20             return root

 

 

 

 

 

 


120. Triangle  【Medium】    返回目录


 

题目:

 

 

解题思路:

用了递归求解的方法,类似求二叉树的最大深度,进行左右子树的递归求解,但是在最后一个测试样例超时了,想了想发现很多路都是重复求解的,所以换成动态规划

 

code:   递归求解超时

 1 def minimumTotal(self, triangle):
 2         """
 3         :type triangle: List[List[int]]
 4         :rtype: int
 5         """
 6         return self.miniTree(triangle,0,0)
 7     def miniTree(self,triangle,i,j):
 8         if len(triangle)-1 == i:
 9             return triangle[i][j]
10         return triangle[i][j] + min(self.miniTree(triangle,i+1,j),self.miniTree(triangle,i+1,j+1))

 

code: 动态规划

1 def minimumTotal(self, triangle):
2         """
3         :type triangle: List[List[int]]
4         :rtype: int
5         """
6         for i in range(len(triangle)-2,-1,-1):
7             for j in range(len(triangle[i])):
8                 triangle[i][j] += min(triangle[i+1][j],triangle[i+1][j+1])
9         return triangle[0][0]

 

 

 

 

 

 

 

 


152. Maximum Product Subarray 【Medium】  返回目录


 题目:

 解题思路:

用一个nxn数组 存dp[i][j]的结果  O(n^2)超时

这个时候就要看题目的特点了,进行简化运算

用一个变量来记录当前最好的结果,并不断比较更新,连乘到当前值的结果与当前值比较,如果还更小,直接断了连乘从当前位置重新开始

Tips:如果在一个数组中要求连续相乘或者相加的最大或最小值,那么当连续的结果还不如当前单个元素时,就要断了重新开始,对于有正负数的乘法时,只需要swap(max,min)

code:  参考答案

 1 def maxProduct(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         if not len(nums):
 7             return 0
 8         res = nums[0]
 9         imax = imin = res
10         for i in range(1,len(nums)):
11             if nums[i] < 0:
12                 imax,imin = imin,imax
13             imax = max(nums[i],imax*nums[i])
14             imin = min(nums[i],imin*nums[i])
15             
16             res = max(res,imax)
17         return res
18         

 

 

 


153. Find Minimum in Rotated Sorted Array【Medium】  返回目录


 

题目:

 解题思路:

类似于 81. Search in Rotated Sorted Array II 进行二分搜索,  最小值要么在第一个位置,要么在右边的第一个

 code:

 1 def findMin(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         l,r = 0,len(nums)-1
 7         if r<0:
 8             return
 9         imin = nums[0]
10         while l<=r:
11             mid = (l+r)//2
12             if nums[mid]<nums[mid-1]:
13                 return min(imin,nums[mid])
14             if nums[0] == nums[mid]:
15                 l += 1
16             elif nums[0] < nums[mid]:  #left
17                 l = mid + 1
18             else:                      #right
19                 r = mid - 1
20         return imin

看了下别人的解法,发现大神们往往都更加注重数据的特点,不会盲目地求解,都是高效利用数据的特点

code: 别人解法

 1 def findMin(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         l,r = 0,len(nums)-1
 7         while l < r:
 8             if nums[l] < nums[r]:
 9                 return nums[l]
10             mid = (l+r)//2
11             if nums[mid] >= nums[l]:
12                 l = mid + 1
13             else:
14                 r = mid
15         return nums[l]

 

 

 

 

 


162. Find Peak Element【Medium】   返回目录


 

题目:

 

解题思路:要求O(logn),那么就是二分法了,直接二分法进行查询即可

 

code:

 1 def findPeakElement(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         l,r = 0,len(nums)-1
 7         if not r:
 8             return 0
 9         while l <= r:
10             mid = (l+r)//2
11             if not mid and nums[mid]>nums[mid+1]:
12                 return mid
13             if mid==len(nums) and nums[mid]>nums[mid-1]:
14                 return mid
15             if 0<mid<len(nums)-1 and nums[mid-1]<nums[mid] and nums[mid]>nums[mid+1]:
16                 return mid
17             elif mid>0 and nums[mid]>nums[mid-1]:
18                 l = mid + 1
19             elif mid>0 and nums[mid]<nums[mid-1]:
20                 r = mid - 1
21             else:
22                 l = l + 1
23         return mid

一道这么简单的题都有好多种算法,算法真是美妙啊

参考别人的优美的解法

code: sequential search O(n)

1 def findPeakElement(self, nums):
2         """
3         :type nums: List[int]
4         :rtype: int
5         """
6         for i in range(1,len(nums)):
7             if nums[i]<nums[i-1]:
8                 return i-1
9         return len(nums)-1

code: binary search

 1 def findPeakElement(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         l,r = 0,len(nums)-1
 7         while l<r:
 8             mid = (l+r)//2
 9             if nums[mid]<nums[mid+1]:
10                 l = mid + 1
11             else:
12                 r = mid
13         return l

学到了,当l<r时,mid+1<=r的,所以一定取得到这个值,就不需要判断范围了,非常简约

 

 

 

 

 

 

 

 

 

 


209. Minimum Size Subarray Sum【Medium】  返回目录


 题目:

 

 

解题思路:我自己的想法之前就是数组所有元素加起来,然后不断减去两头比较小的数,但是有个问题就是当两头数字一样时就不确定要减去哪个,所以行不通

参考别人做法,O(n)算法就是使用两个指针,这样不断r++,l--就保持住了中间结果,只需要加减一个元素; O(nlogn)的做法就是先用O(n)算出个累加和的数组,然后又二分法进行查找

比如说:nums = [2, 3, 1, 2, 4, 3]    sums = [0, 2, 5, 6, 8, 12, 15]   然后遍历数组作为i, r就在后面的数字中二分查找第一个>=sums[i]+s的数,   为什么要作累加和呢,因为这样就可以保证数组是升序的,可以很方便的利用二分法

 

code: O(N) 

 1 def minSubArrayLen(self, s, nums):
 2         """
 3         :type s: int
 4         :type nums: List[int]
 5         :rtype: int
 6         """
 7         res = 0
 8         l,r = 0,-1
 9         min_len = len(nums)
10         flag = False
11         while r<len(nums)-1:
12             r += 1
13             res += nums[r]
14             while res >= s:
15                 flag = True
16                 min_len = min(min_len, r-l+1)
17                 res -= nums[l]
18                 l += 1
19         return min_len if flag else 0

code: O(NlogN)

 1 def minSubArrayLen(self, s, nums):
 2         """
 3         :type s: int
 4         :type nums: List[int]
 5         :rtype: int
 6         """
 7         sums = [0]
 8         nums_len = len(nums)
 9         for i in range(nums_len):
10             sums.append(nums[i]+sums[i])
11         min_len = float('inf')
12         for i in range(nums_len):
13             j = self.binary_search(sums,i,nums_len+1,sums[i]+s)
14             if j==-1:
15                 break
16             min_len = min(min_len,j-i)
17         return min_len if min_len!=float('inf') else 0
18     def binary_search(self,nums,i,nums_len,target):
19         l,r = i,nums_len-1
20         while l<r:
21             mid = (l+r)//2
22             if nums[mid]>=target:
23                 r = mid
24             else:
25                 l = mid + 1
26         return l if nums[l]>=target else -1

 

 

 

 

 

 


216. Combination Sum III【Medium】  返回目录


 题目:

 解题思路:和之前的 39. Combination Sum 一个套路

code:

 1 def combinationSum3(self, k, n):
 2         """
 3         :type k: int
 4         :type n: int
 5         :rtype: List[List[int]]
 6         """
 7         nums = [1,2,3,4,5,6,7,8,9]
 8         res = []
 9         self.find(res,nums,0,k,[],n)
10         return res
11     def find(self,res,nums,index,k,path,remains):
12         if len(path)==k and not remains:
13             res.append(path)
14             return
15         if len(path)==k:
16             return
17         for i in range(index,len(nums)):
18             self.find(res,nums,i+1,k,path+[nums[i]],remains-nums[i])
19         

 

 

 

 

 

 


228. Summary Ranges【Medium】  返回目录


 

题目:

 解题思路:直接从左到右遍历一遍 O(N)

code:

 1 def summaryRanges(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[str]
 5         """
 6         res = []
 7         i = 0
 8         while i<len(nums)-1:
 9             temp = str(nums[i])
10             while i<len(nums)-1 and nums[i+1] == nums[i]+1:
11                 i += 1
12             if i>0 and nums[i]==nums[i-1]+1:
13                 temp = temp + "->" + str(nums[i])
14             res.append(temp)
15             i += 1
16         if i==len(nums)-1:
17             res.append(str(nums[-1]))
18         return res

 

 

 

 


229. Majority Element II【Medium】   返回目录


 

题目:

 解题思路:

自己完全没想法,看了参考答案,发现了一个叫做 Boyer-Moore Majority Vote algorithm(摩尔投票算法),可以解决求无序数列中多于n/2, n/3....的元素。

对于大于一半的数很简单,就是用两个变量,一个candidate记录可能是结果的元素,一个count记录当前的个数,当count为0时,candidate就设置为当前数字,如果当前数字和candidate一样,count++, 如果不同,count--,就相当于一直在找不一样的一对数字,找到了就消去这两个数字(类似于连连看),那么最后剩下的数字就是最终结果了,对于大于n/3的元素,就需要设置两个candidate,算法同上,只不过最后判断是否是真的结果时,还需要遍历一遍进行确认。

code: 参考

 1 def majorityElement(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[int]
 5         """
 6         count1 = count2 = 0
 7         candidate1 = candidate2 = None
 8         for i in range(len(nums)):
 9             if nums[i] == candidate1:
10                 count1 += 1
11             elif nums[i] == candidate2:
12                 count2 += 1   
13             elif not count1:
14                 candidate1 = nums[i]
15                 count1 += 1
16             elif not count2:
17                 candidate2 = nums[i]
18                 count2 += 1
19             else:
20                 count1 -= 1
21                 count2 -= 1
22         res = []
23         if nums.count(candidate1) > len(nums)//3:
24             res.append(candidate1)
25         if nums.count(candidate2) > len(nums)//3:
26             res.append(candidate2)
27         return res

感觉自己写代码还是不够简洁,虽然思想一样,但是大神的代码看起来就是简洁有美感

 1 def majorityElement(self, nums):
 2     if not nums:
 3         return []
 4     count1, count2, candidate1, candidate2 = 0, 0, 0, 1
 5     for n in nums:
 6         if n == candidate1:
 7             count1 += 1
 8         elif n == candidate2:
 9             count2 += 1
10         elif count1 == 0:
11             candidate1, count1 = n, 1
12         elif count2 == 0:
13             candidate2, count2 = n, 1
14         else:
15             count1, count2 = count1 - 1, count2 - 1
16     return [n for n in (candidate1, candidate2)
17                     if nums.count(n) > len(nums) // 3]

 

 

 

 

 

 


238. Product of Array Except Self【Medium】   返回目录


 题目:

 

 解题思路:

不让用除法,那么就用乘法,用两个数组left_mul和right_mul分别记录从左到右和从右到左累乘的结果,然后res[i]=left[i-1]*right[i+1]

这样的话花费时间 O(n)  花费空间也是O(n)

额外的奖励就是希望能用O(1)的空间解决

code:  O(n) time  O(n) space

 1 def productExceptSelf(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[int]
 5         """
 6         left_mul = [1]
 7         for num in nums:
 8             left_mul.append(num*left_mul[-1])
 9         right_mul = [ 1 for i in range(len(nums)+1)] 
10         for i in range(len(nums)-1,-1,-1):
11             right_mul[i] = nums[i]*right_mul[i+1]
12         res = []
13         for i in range(len(nums)):
14             res.append(left_mul[i]*right_mul[i+1])       
15         return res

我这个思路是正确的,怎么将上面的代码修改成O(1) space呢(不包括res占的空间),那么就只能用res数组表示left_mul,然后right数组用一个right变量表示就行

code: 参考别人的

 1 def productExceptSelf(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[int]
 5         """
 6         res = [1]
 7         for i in range(1,len(nums)):
 8             res.append(res[i-1]*nums[i-1])
 9         right = 1
10         for i in range(len(nums)-1,-1,-1):
11             res[i] *= right
12             right *= nums[i]
13         return res

 

 

 

 


287. Find the Duplicate Number 【Medium】   返回目录


 题目:

 解题思路:

不能修改原数组且只能用O(1) space,也就是说不能对原数组进行排序,参考别人的解法,发现用链表进行判断环路的方法可以用O(n)的方法实现

有两个箭头指向1,说明有环路了,而重复的数字呢就是这个环路的入口元素,首先要找到这个环路,然后再找到入口元素。

找环路过程用两个指针,一个fast,一个slow,fast一次走两步,slow一次走一步,它们两个总是会在环路内部相遇的

设环路前面的一段路长k,当slow走到入口处时,fast已经走到环路上的k处,假设它们再走c次相遇,那么c = n-k,也就是说他们的相遇点在slow走上环路后的c位置

那么求入口位置就可以很好计算了,因为c = n-k, 那么用一个A指针从头开始走起,然后从相遇的地方B指针走起,两个指针都是一次走一步,那么相遇的地方就是入口处,因为两个指针都走k步就相同了

 code:  O(n)  判断链表中的环路   

 1 def findDuplicate(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         if not len(nums):
 7             return
 8         slow,fast = nums[0],nums[nums[0]]
 9         while slow!= fast:
10             slow = nums[slow]
11             fast = nums[nums[fast]]
12         fast = 0
13         while fast!=slow:
14             fast = nums[fast]
15             slow = nums[slow]
16         return slow

 还看到有一种二分的解法O(nlogn)就是对[1,n]二分查找,对mid,统计小于mid的个数O(n),如果count[mid]>mid,说明在[1,mid]部分有重复的元素,否则就在[mid:]里面

总的时间复杂度就是O(nlogn)

code: O(nlogn)

 1 def findDuplicate(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         if not len(nums):
 7             return
 8         l,r = 1,len(nums)-1
 9         while l<r:
10             mid = (l+r)//2
11             count = 0
12             for num in nums:
13                 if num<= mid:
14                     count += 1
15             if count>mid:
16                 r = mid
17             else:
18                 l = mid+1
19         return l

注意一个问题,我经常把r=mid 写成r=mid-1   当nums<=mid情况下左边是包含mid的,注意是否要考虑mid的情况

 

 

 

 

 


289. Game of Life 【Medium】  返回目录


 题目:

 解题思路:

要求in-place所以不能有额外的空间,所有信息都必须存在当前board上,但是又不能冲刷掉前面的信息,想不到怎么弄,看参考答案

说是用2bit数[0-3]来代表第一个bit表示下个状态,第二个bit表示当前状态,这样既可以存当前信息也可以存历史信息,bravo!!!!!!

比如说 00  当前状态dead  下一个状态dead     01   当前状态live  下个状态dead

而且还有个好处就是这样设置就可以很方便地使用位操作  取当前状态 board[i][j] & 1   取下一个状态  board[i][j] >> 1

code:   O(mn) time   O(1) space

 1 def gameOfLife(self, board):
 2         """
 3         :type board: List[List[int]]
 4         :rtype: void Do not return anything, modify board in-place instead.
 5         """
 6         m = len(board)
 7         if not m:
 8             return
 9         n = len(board[0])
10         for i in range(m):
11             for j in range(n):
12                 live = self.neibor(board,m,n,i,j)
13                 if board[i][j] == 1 and live>=2 and live<=3:  #current alive
14                     board[i][j] = 3
15                 elif not board[i][j] and live==3:    #current dead
16                     board[i][j] = 2
17         for i in range(m):
18             for j in range(n):
19                 board[i][j] >>= 1
20     def neibor(self,board,m,n,i,j):
21         live = 0 - (board[i][j] & 1)    
22         for p in range(max(i-1,0),min(i+2,m)):
23             for q in range(max(j-1,0),min(j+2,n)):
24                 live += board[p][q] & 1
25         return live

 

注意:  0 - 1 & 1结果是1  要加上括号才是正确结果-1   +/-的优先级比 &高 比&&低

最后一段关于边界判断的看别人写法是在太妙,自己写都是额外的if判断

 

 

 

 

 


380. Insert Delete GetRandom O(1) 【Medium】   返回目录


 

题目:

 

 解题思路:

O(1)时间复杂度,不就是hash表吗,在python中体现为dict字典,可是对于字典它remove的时候不太好操作,因为要遍历index,所以这里就需要用列表存数据,用dict存index

 1 import random
 2 class RandomizedSet:
 3 
 4     def __init__(self):
 5         """
 6         Initialize your data structure here.
 7         """
 8         self.nums = []
 9         self.length = 0
10         self.index = {}
11         
12 
13     def insert(self, val):
14         """
15         Inserts a value to the set. Returns true if the set did not already contain the specified element.
16         :type val: int
17         :rtype: bool
18         """
19         if val not in self.index:
20             self.nums.append(val)
21             self.length += 1 
22             self.index[val] = self.length - 1
23             return True
24         return False
25         
26 
27     def remove(self, val):
28         """
29         Removes a value from the set. Returns true if the set contained the specified element.
30         :type val: int
31         :rtype: bool
32         """
33         if val in self.index:
34             ind,last = self.index[val],self.nums[-1]
35             self.nums[ind],self.index[last] = last,ind
36             self.nums.pop()
37             self.index.pop(val)
38             self.length -= 1
39             return True
40         return False
41         
42 
43     def getRandom(self):
44         """
45         Get a random element from the set.
46         :rtype: int
47         """
48         return self.nums[random.randint(0, self.length-1)]
49 
50 
51 # Your RandomizedSet object will be instantiated and called as such:
52 # obj = RandomizedSet()
53 # param_1 = obj.insert(val)
54 # param_2 = obj.remove(val)
55 # param_3 = obj.getRandom()

 

 

 

 

 

 

 


442. Find All Duplicates in an Array【Medium】   返回目录


 题目:

 解题思路:

O(n)时间 不许有额外空间  好难啊,想不出,看参考答案,真是精妙啊,感觉每天都要被各种设计巧妙的算法惊艳

如果不能使用额外的空间,那么就需要在当前已有的数组上看能否存上额外的信息,比如289. Game of Life 本身是0/1扩展成多位数据,用多出来的位数存储额外信息

这里使用当前元素的正负号作为额外的信息保存到当前数组,对数字i 用i-1(减一是因为1~n换成index从0开始)位置上元素负号表示已经出现过一次了,这样遍历完成后,所有负数对应index+1就是duplicates

 code: O(n)   beat 100%  第一次100% 虽然是参考的答案,但是还是很感动啊,算法真的是很美妙,我爱算法!!

 1 def findDuplicates(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[int]
 5         """
 6         res = []
 7         for num in nums:
 8             num = abs(num)
 9             if nums[num-1]<0:
10                 res.append(num)
11             else:
12                 nums[num-1] = -nums[num-1]
13         return res

 

还看到了另外一种算法也是beat100%    666~

将数组中的值与index对应,对应不上的多余值 [2,3]就是duplicates

code:

 1 def findDuplicates(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: List[int]
 5         """
 6         i = 0
 7         res = []
 8         while i < len(nums):
 9             if nums[i]!=nums[nums[i]-1]:
10                 temp = nums[nums[i]-1]
11                 nums[nums[i]-1] = nums[i]
12                 nums[i] = temp
13                 #nums[i],nums[nums[i]-1] = nums[nums[i]-1],nums[i]   wrong because nums[nums[i]-1]中也用到了nums[i]
14             else:
15                 i += 1
16         for i in range(len(nums)):
17             if nums[i]!=i+1:
18                 res.append(nums[i])
19         return res

 

 从头遍历循环,对于i直到找到与它相同的元素否则不断交换,每一次交换都一定确定了一个位置的正确对应,然后再移到下一个位置

 

 

 


495. Teemo Attacking【Medium】   返回目录


 题目:

 

 解题思路:

这道题很简单,就是一个数轴覆盖长度问题,用一个end变量记录下当前覆盖到的最大长度,然后再进行覆盖的时候和它比较一下

code:   beat 2.5%

 1 def findPoisonedDuration(self, timeSeries, duration):
 2         """
 3         :type timeSeries: List[int]
 4         :type duration: int
 5         :rtype: int
 6         """
 7         res = 0
 8         end = 0
 9         for i in range(len(timeSeries)):
10             if timeSeries[i]+duration > end:
11                 res += min(timeSeries[i]+duration-end,duration)
12             end = max(end,timeSeries[i]+duration)
13         return res

 

 

别人的解法:  beat 25%

1 def findPoisonedDuration(self, timeSeries, duration):
2         ans = duration * len(timeSeries)
3         for i in range(1,len(timeSeries)):
4             ans -= max(0, duration - (timeSeries[i] - timeSeries[i-1]))
5         return ans

 

 

 

 

 

 

 


560. Subarray Sum Equals K【Medium】   返回目录


 

题目:

 解题思路:

这道题指明是整数,没有说是正整数,所以用变量保存当前和,然后减去头加上尾的方式不可行,那么首先先想暴力方法O(n)  sum(i,j)

想要进行优化,那么就事先求出presum  sum(i,j)=sum(j)-sum(i)

在遍历过程中同时寻找满足sum(j)-sum(i)==k 的i

code: O(n) time  O(n) space

 1 def subarraySum(self, nums, k):
 2         """
 3         :type nums: List[int]
 4         :type k: int
 5         :rtype: int
 6         """
 7         accu_sum = {0:1}
 8         res = s = 0
 9         for num in nums:
10             s += num
11             res += accu_sum.get(s-k,0)
12             accu_sum[s] = accu_sum.get(s,0)+1
13         return res

 

 

 

 

 


 565. Array Nesting【Medium】  返回目录


 题目:

解题思路:

暴力搜索呗,$O(n^2)$  超时了

 1 def arrayNesting(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         res = 0
 7         for i in range(len(nums)):
 8             count = 0
 9             k = i
10             while(nums[k]>0 and nums[k]!=i):
11                 k = nums[k]
12                 count += 1
13             res = max(res,count+1)
14         return res

 

 想想改进的方法:想不出,参考别人答案   O(n)

 1 def arrayNesting(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         res = 0
 7         for i in range(len(nums)):
 8             count = 0
 9             k = i
10             while(nums[k]>0 and nums[k]!=i):
11                 temp = k
12                 k = nums[k]
13                 nums[temp] = -1
14                 count += 1
15             res = max(res,count+1)
16         return res

 

其实不同之处就是多加了两句话,当遍历过一遍后就标记之后不再遍历,原因是如下,其实这是形成了多个环,当你第一步踏进一个环时,长度就是该环的长度,所以说看第一步踏进了与之前不同的环,得出的结果才可能不同

 

 

 

 

 

 

 


611. Valid Triangle Number【Medium】   返回目录


 题目:

 解题思路:

先确定两条边,然后确定另外一条边,确定两条边的时候$O(n^2)$,所以先排序确定第三条边的时候用遍历超时了

code:   O(TLE)  $O(n^3)$

 1 def triangleNumber(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         nums.sort()
 7         res = 0
 8         for i in range(len(nums)):
 9             for j in range(i+1,len(nums)):
10                 l = abs(nums[i]-nums[j])
11                 r = nums[i]+nums[j]
12                 for k in range(j+1,len(nums)):
13                     if nums[k]>=r:
14                         break
15                     elif nums[k]<=l:
16                         continue
17                     else:
18                         res += 1
19         return res

 参考别人答案,发现,审题很重要,发现题目的一些特殊性质很重要,比如说能构成三角形的条件,我之前设置的条件就太复杂了,其实只要满足两小边之和大于最大边就行了

因为,已知 a,b < c   如果a+b>c => a>c-b && b>c-a

而且如果按升序排好,倒着来取最大边c,那么只需要对当前index前面取两个数满足 a+b>c即可,同时a,b的取法也是由[0,index-1]两端取法,这样的话当0,index-1满足条件,那么0~index-1中间的数都可作为a满足,因为是逐渐变大的,所以这时的取值可能情况是index-1-0+1,同时b的下标减一,求另外的解法;若这时取值a+b<=c,只需要移动a的下标加一让数字变大即可

 1 def triangleNumber(self, nums):
 2         """
 3         :type nums: List[int]
 4         :rtype: int
 5         """
 6         nums.sort()
 7         res = 0
 8         for i in range(len(nums)-1,1,-1):
 9             l,r = 0,i-1
10             while l<r:
11                 if nums[l]+nums[r]>nums[i]:
12                     res += r-l
13                     r -= 1
14                 else:
15                     l += 1
16         return res

 

 

 

 

 

 

 


621. Task Scheduler【Medium】    返回目录


 题目:

 解题思路:

这题因为所有任务都是等间距的,所以想用贪心法做,先对所有任务的耗时进行反向排序,用一个长度为n的数组记录下可填充的每列的end位置,当要填充一个任务时,就看min(end)进行填充就好了

代码如下,错了,可以通过58个测试,剩下的测试过不了

 1 def leastInterval(self, tasks, n):
 2         """
 3         :type tasks: List[str]
 4         :type n: int
 5         :rtype: int
 6         """
 7         if not n:
 8             return len(tasks)
 9         count = {}
10         for t in tasks:
11             count[t] = count.get(t,0)+1
12         nums = sorted(count.values(),reverse=True)
13         end = [-i for i in range(n+1,0,-1)]
14         for i in nums:
15             ind = end.index(min(end))
16             end[ind] += i*(n+1)
17         return max(end)+1

 

参考别人的解法,发现这种贪心算法是有问题的,可以不连续,反而是间隔着插入

主要是找到这个排列的规律

 正确的code如下:

 1 def leastInterval(self, tasks, n):
 2         """
 3         :type tasks: List[str]
 4         :type n: int
 5         :rtype: int
 6         """
 7         task_counts = list(collections.Counter(tasks).values())
 8         M = max(task_counts)
 9         Mct = task_counts.count(M)
10         return max(len(tasks), (M - 1) * (n + 1) + Mct)

 

 

 

 

 

 


667. Beautiful Arrangement II【Medium】  返回目录


 

题目:

Example1:

Input: n = 3, k = 1
Output: [1, 2, 3]
Explanation: The [1, 2, 3] has three different positive integers ranging from 1 to 3, and the [1, 1] has exactly 1 distinct integer: 1.

 Example2:

Input: n = 3, k = 2
Output: [1, 3, 2]
Explanation: The [1, 3, 2] has three different positive integers ranging from 1 to 3, and the [2, 1] has exactly 2 distinct integers: 1 and 2.

 

 解题思路:

如果有k种间距的话,那么就是k,k-1,k-2,....1   所以将  1,k+1, 2, k, 3, k-1,.......   就有间距 k,k-1,k-2,k-3,k-4,以此类推

code:   完全自己想的,一遍过,好开心

 1 def constructArray(self, n, k):
 2         """
 3         :type n: int
 4         :type k: int
 5         :rtype: List[int]
 6         """
 7         res = [i+1 for i in range(n)]
 8         j = 1
 9         for i in range(0,k+1,2):
10             res[i] = j
11             j += 1
12         j = k+1
13         for i in range(1,k+1,2):
14             res[i] = j
15             j -= 1
16         return res

 

 

 

 

 

 

 

 

 

 

 


670. Maximum Swap【Medium】   返回目录


 题目:

给一个非负整数,只能交换两个数位上的数组,给出交换后可能的结果中的最大值

 

解题思路:

想着说先倒序排序,然后对比原数和倒序排序后数,第一个遇到的不一样的数字进行交换,结果发现当有相同数字时,不知道该交换哪个,还是思考得不够周全

code:  wrong

 1 def maximumSwap(self, num):
 2         """
 3         :type num: int
 4         :rtype: int
 5         """
 6         num_str = list(str(num))
 7         num_max = sorted(num_str,reverse=True)
 8         i = 0
 9         while(i<len(num_str) and num_str[i]==num_max[i]):
10             i += 1
11         if i != len(num_str):
12             ind = i+num_str[i:].index(num_max[i])
13             num_str[i],num_str[ind] = num_str[ind],num_str[i]
14         return int("".join(num_str))

 

code: 考虑上述情况的修改后AC代码  O(NlogN)

 1 def maximumSwap(self, num):
 2         """
 3         :type num: int
 4         :rtype: int
 5         """
 6         num_str = list(str(num))
 7         num_max = sorted(num_str,reverse=True)
 8         i = 0
 9         while(i<len(num_str) and num_str[i]==num_max[i]):
10             i += 1
11         res = num
12         if i != len(num_str):
13             candidates = [k for (k,v) in enumerate(num_str[i:]) if v==num_max[i]]
14             for j in candidates:
15                 num_str[i],num_str[i+j] = num_str[i+j],num_str[i]
16                 res = max(res,int("".join(num_str)))
17                 num_str[i],num_str[i+j] = num_str[i+j],num_str[i]
18         return res

 

上述算法因为要排序,所以是O(nlogn)算法 

在本题中数据长度最多为8,所以无所谓,若是没有这个限制呢,所以还是需要更优的解法

看了下别人的解法,和我真的是相同的想法,但是实现得很精妙,而且比我想得更加透彻,首先因为n比较小所以不要用O(nlogn)进行排序,反而是用O(n)记录下每个数字出现的最后一次的index,交换从大到小的数字,只要遇到不相等的,就用最后的那个数交换,这里就是比我精妙的地方,我是顺序遍历,人家倒序遍历找交换的位置,机智,这样就不用再比较结果了

 1 def maximumSwap(self, num):
 2         """
 3         :type num: int
 4         :rtype: int
 5         """
 6         num_str = list(str(num))
 7         last_index = {}
 8         for i in range(len(num_str)):
 9             last_index[num_str[i]] = i
10         for i in range(len(num_str)):
11             for k in range(9,0,-1):
12                 ind = last_index.get(str(k),None)
13                 if ind and ind>i and num_str[ind]>num_str[i]:
14                     num_str[ind],num_str[i] = num_str[i],num_str[ind]
15                     return int("".join(num_str))
16         return num    

 

 

 

 


713. Subarray Product Less Than K【Medium】   返回目录


 

题目:

Example1:

Input: nums = [10, 5, 2, 6], k = 100
Output: 8
Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6].
Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.

 

 解题思路:

因为全部都是正整数,所以可以用temp记录下当前index连乘后的结果,然后除去nums[index]作为index+1的起始结果,这样的话可以简化很多计算,注意想问题时,一定要想清楚变量具体代表的什么含义,才能对初始值或者计算式进行良好地定义。

code:错了,只通过了78/84个测试样例,说明考虑得还不够全面,漏掉了一些特殊情况

 1 def numSubarrayProductLessThanK(self, nums, k):
 2         """
 3         :type nums: List[int]
 4         :type k: int
 5         :rtype: int
 6         """
 7         if not k:
 8             return 0
 9         nums.append(1)
10         res = 0
11         temp = 1
12         j = 0
13         for i in range(len(nums)-1):
14             temp = temp//nums[i-1]
15             res += max(j-i,0)
16             temp = temp * nums[j]
17             while temp<k:
18                 res += 1
19                 j = j+1
20                 if j<len(nums)-1:
21                     temp = temp*nums[j]
22                 else:
23                     return res+(j-1-i)*(j-i)//2
24             temp = temp // nums[j]
25         return res

看了下参考答案,思路都是差不多,就是实现方法更全面,而且考虑的情况更加全面,我真的应该学习下写代码的自我修养

 code:  参考别人

 1 def numSubarrayProductLessThanK(self, nums, k):
 2         """
 3         :type nums: List[int]
 4         :type k: int
 5         :rtype: int
 6         """
 7         if k<= 1:
 8             return 0
 9         res = 0
10         temp = 1
11         j = 0
12         for i in range(len(nums)):
13             if i>0 and i<=j:
14                 temp = temp//nums[i-1]
15             else:
16                 j = i
17             while j<len(nums) and temp*nums[j]<k:
18                 temp = temp*nums[j]
19                 j += 1
20             res += j-i
21         return res

 

 对比这两份代码

主要是没有开头的if-else的判断j代表的是正好<k的下标加一;temp是正好<k的连乘

 

 

 

 

 

 

 

 

 

 


714. Best Time to Buy and Sell Stock with Transaction Fee【Medium】  返回目录


 题目:

解题思路:

从开头开始找上坡,如果上坡减去fee>0(第一个坡)  如果可连续,对于续上的坡,只需要坡>之前下降的部分就可以直接续上,而且不用再交费用了,如果续不上直接断掉

提交了一个版本的代码发现只能通过26/44个测试样例

code:  wrong 26/44

 1 def maxProfit(self, prices, fee):
 2         """
 3         :type prices: List[int]
 4         :type fee: int
 5         :rtype: int
 6         """
 7         i = 1
 8         res = 0
 9         concat = False
10         remain = 0
11         while i<len(prices):
12             start = prices[i-1]
13             while(i<len(prices) and prices[i]>=prices[i-1]):
14                 i += 1
15             if concat:
16                 if prices[i-1]-start>=remain:
17                     res += prices[i-1]-start-remain
18                 else:
19                     concat = False
20                     remain = 0
21             else:
22                 if prices[i-1]-start>=fee:
23                     res += prices[i-1]-start-fee
24                     concat = True
25             start = prices[i-1]
26             while(i<len(prices) and prices[i]<=prices[i-1]):
27                 i += 1
28             if start-prices[i-1]>fee:
29                 concat = False
30             else:
31                 concat = concat and True
32                 if concat:
33                     remain = start-prices[i-1]
34         return res

 

但是发现这个代码有种情况没考虑到,就是前面短后面长的情况考虑不到,所以还是应该把它转换成连续子数组和的方式

修改了一个版本,还是有问题,想不明白自己家还少考虑了哪一部分

code: 22/44 pass

 1 def maxProfit(self, prices, fee):
 2         """
 3         :type prices: List[int]
 4         :type fee: int
 5         :rtype: int
 6         """
 7         if len(prices)<= 1:
 8             return 0
 9         earn = []
10         res = 0
11         i = 0
12         flag = False    
13         while i < len(prices)-1:
14             start = prices[i]
15             while i<len(prices)-1 and prices[i+1]>=prices[i]:
16                 i += 1
17                 flag = True
18             if flag:
19                 earn.append(prices[i]-start)
20             if i <len(prices)-1:
21                 start = prices[i]
22                 while i<len(prices)-1 and prices[i+1]<=prices[i]:
23                     i += 1
24                 earn.append(prices[i]-start)
25         
26         concat = False
27 
28         print(earn,len(earn))
29 
30         i = 0
31         remain = 0
32         while i < len(earn)-2:
33             # import pdb
34             # pdb.set_trace()
35             if not concat:
36                 while i < len(earn)-2 and earn[i]<=0:
37                     i += 1
38                 if earn[i]>=fee:
39                     res += earn[i]-fee
40                     concat = True
41                 elif earn[i]+earn[i+1]>0:
42                     remain = earn[i]+earn[i+1]
43                     concat = True
44                     i += 2 
45                 else:
46                     i += 2
47             else:
48                 if remain>0:
49                     if remain + earn[i] > fee:
50                         res += remain + earn[i] - fee
51                         remain = 0
52                     elif earn[i]+earn[i+1]>0:
53                         remain += earn[i]+earn[i+1]
54                         i += 2
55                     else:
56                         concat = False
57                         i += 2
58                         remain = 0
59                 else:
60                     if abs(earn[i+1])<=min(earn[i+2],fee):
61                         res += earn[i+1]+earn[i+2]
62                         i += 2
63                     else:
64                         concat = False
65                         i = i+2   
66         if not concat and earn[i]>fee:
67             res += earn[i]-fee
68         return res

 

开始做题前没完全考虑清楚所有的可能性,经常就是写完code后只能通过部分测试样例,下笔前请好好思考清楚

参考答案,真的太厉害了

用s0表示当前手上没有股票利润

用s1表示当前手上有一只股票时的利润

code:

 1 def maxProfit(self, prices, fee):
 2         """
 3         :type prices: List[int]
 4         :type fee: int
 5         :rtype: int
 6         """
 7         s0 = 0
 8         s1 = -float('inf')
 9         for p in prices:
10             tmp = s0
11             s0 = max(s0,s1+p)
12             s1 = max(s1,tmp-p-fee)
13         return s0

代码中先是-p1,  然后是+p2 其实就是求一个p2-p1过一天赚的利润,只是通过这种方式的话就只需要O(1) space  不需要额外的空间保存每天的利润,真是太巧妙了 

太精妙了,我要给这道题打三颗星

 

 

 

 

 


718. Maximum Length of Repeated Subarray【Medium】   返回目录


 题目:

 解题思路:

固定A,每次将B往后滑动一个index与A对齐,计算最大res,然后交换A,B的位置再求一次 ,取最大的结果,居然一遍AC了,感动,但是耗时有点多$O(n^2)$

code:

 1 def findLength(self, A, B):
 2         """
 3         :type A: List[int]
 4         :type B: List[int]
 5         :rtype: int
 6         """
 7         res = 0
 8         for i in range(len(A)):
 9             res = max(res,self.compare(A,i,B))
10         for i in range(len(B)):
11             res = max(res,self.compare(B,i,A))
12         return res
13     def compare(self,A,k,B):
14         i,j = k,0
15         res = 0
16         while i<len(A):
17             while i<len(A) and A[i]!=B[j]:
18                 i += 1
19                 j += 1
20             temp = i
21             while i<len(A) and A[i]==B[j]:
22                 i += 1
23                 j += 1
24             res = max(res,i-temp)
25         return res

 

 

 

 

 


729. My Calendar I【Medium】   返回目录


 题目:

 解题思路:

设置interval数组,然后每book一次就对interval数组进行遍历比较,如果没有重合就插入返回True,否则返回False

code: TLE    73 / 108 test cases passed.

 1 class MyCalendar:
 2 
 3     def __init__(self):
 4         self.interval = []
 5 
 6     def book(self, start, end):
 7         """
 8         :type start: int
 9         :type end: int
10         :rtype: bool
11         """
12         for i in range(len(self.interval)):
13             if self.interval[i][0]<=start<self.interval[i][1] or self.interval[i][0]<end<=self.interval[i][1] or (self.interval[i][0]>start and self.interval[i][1]<end):
14                 return False
15         self.interval.append([start,end])
16         return True
17         
18 
19 
20 # Your MyCalendar object will be instantiated and called as such:
21 # obj = MyCalendar()
22 # param_1 = obj.book(start,end)

 看了下答案,同样是暴力搜索,人家技巧就是更高,只改动一句

TLE  108/108 passed

 1 class MyCalendar:
 2 
 3     def __init__(self):
 4         self.interval = []
 5 
 6     def book(self, start, end):
 7         """
 8         :type start: int
 9         :type end: int
10         :rtype: bool
11         """
12         for i in range(len(self.interval)):
13             if not (self.interval[i][0]>=end or self.interval[i][1]<=start):
14                 return False
15         self.interval.append([start,end])
16         return True
17         
18 
19 
20 # Your MyCalendar object will be instantiated and called as such:
21 # obj = MyCalendar()
22 # param_1 = obj.book(start,end)

再换成tuple   真是有毒,这样就能直接pass     732ms

 1 class MyCalendar:
 2 
 3     def __init__(self):
 4         self.intervals = []
 5 
 6     def book(self, start, end):
 7         """
 8         :type start: int
 9         :type end: int
10         :rtype: bool
11         """
12         for s,e in self.intervals:
13             if not (start>=e or end<=s):
14                 return False
15         self.intervals.append((start,end))
16         return True
17 
18 
19 # Your MyCalendar object will be instantiated and called as such:
20 # obj = MyCalendar()
21 # param_1 = obj.book(start,end)

tuple创建速度明显快于list, 遍历速度差不多,唯一缺点就是不可更改

 还有,做比较时,能简洁点儿就简洁一点,这样速度会更快一点

还有些别的解法,使用二叉树和红黑树,红黑树在python中需要手动实现,这里就不放了,下面是二叉树的实现,参考的答案

code:  二叉树   378ms  果然快很多

 1 class Node:
 2     def __init__(self,s,e):
 3         self.e = e
 4         self.s = s
 5         self.left = None
 6         self.right = None
 7         
 8 class MyCalendar:
 9     
10     def __init__(self):
11         self.root = None
12     
13     def book_helper(self,s,e,node):
14         if s >= node.e:
15             if node.right:
16                 return self.book_helper(s,e,node.right)
17             else:
18                 node.right = Node(s,e)
19                 return True
20         elif e <= node.s:
21             if node.left:
22                 return self.book_helper(s,e,node.left)
23             else:
24                 node.left = Node(s,e)
25                 return True
26         else:
27             return False
28 
29     def book(self, start, end):
30         """
31         :type start: int
32         :type end: int
33         :rtype: bool
34         """
35         if not self.root:
36             self.root = Node(start,end)
37             return True
38         return self.book_helper(start,end,self.root)
39 
40 # Your MyCalendar object will be instantiated and called as such:
41 # obj = MyCalendar()
42 # param_1 = obj.book(start,end)

 

 

 

 

 

 


731. My Calendar II【Medium】   返回目录


题目:

 解题思路:

一直想着说用二叉树做,但是对于重合的部分不知道怎么处理,就用三叉树做,用mid节点表示第一次的冲突部分;然后看了下参考答案,直接暴力搜索, 人家写的很简洁巧妙

 1 class MyCalendarTwo:
 2 
 3     def __init__(self):
 4         self.overlaps = []
 5         self.calendar = []
 6     
 7     def book(self,start,end):
 8         for i,j in self.overlaps:
 9             if not (start>=j or end<=i):
10                 return False
11         for i,j in self.calendar:
12             if not (start>=j or end<=i):
13                 self.overlaps.append((max(start,i),min(end,j)))
14         self.calendar.append((start,end))
15         return True             

 

  

 

转载于:https://www.cnblogs.com/lainey/p/7741583.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值