• 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             

      

  • 相关阅读:
    适配器模式
    快排变种
    美团面试问题
    gulp前端自动化构建工具新手入门篇
    javascript继承
    .call()和.apply()相同点与不同点
    JavaScript原型,原型链 !
    锚点链接和hash属性
    构造函数与普通函数的比较
    JS的作用域和作用域链
  • 原文地址:https://www.cnblogs.com/lainey/p/7741583.html
Copyright © 2020-2023  润新知