时间不多了 我要在这个月底把数据结构给完整的一遍,在阅读论文的同时认真地将算法好好的复习一遍,不多说了,开始!
题目链接:1. 两数之和
题目大意:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
'''
# 很耗时!
# 使用数组双循环的方法并不好用 很慢
for i in range(len(nums)-1):
for j in range(i+1,len(nums)):
if nums[i]+nums[j] == target:
return [i,j]
'''
# 使用字典的方法 要快不少
# 把看过的数组的下标存起来 调用要比双循环 在时间上快不少
vis = dict()
for i,num in enumerate(nums):
if target-num in vis:
return [vis[target-num],i]
vis[num] = i
题目链接:4. 寻找两个正序数组的中位数
题目大意:给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应该为 O(log (m+n)) 。
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
def getKthElement(k: int) -> float:
id1,id2 = 0,0
while 1:
if id1 == n1:
return nums2[id2+k-1]
if id2 == n2:
return nums1[id1+k-1]
if k == 1:
return min(nums1[id1],nums2[id2])
newId1 = min(id1+(k//2-1),n1-1)
newId2 = min(id2+(k//2-1),n2-1)
num1,num2 = nums1[newId1],nums2[newId2]
if num1 <= num2:
k -= newId1-id1+1
id1 = newId1+1
else:
k -= newId2-id2+1
id2 = newId2+1
n1,n2 = len(nums1),len(nums2)
n = n1+n2
if n%2 != 0:
return getKthElement(n//2+1)
else:
return (getKthElement(n//2)+getKthElement(n//2+1))/2
题目链接:11. 盛最多水的容器
题目大意:给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。说明:你不能倾斜容器。
解题思路: 双头指针
tmp = (R-L)*min(height[L],height[R])
class Solution:
def maxArea(self, height: List[int]) -> int:
L,R = 0,len(height)-1
ans = 0
while L<R:
# 矩形的长为 R-L 高为 min(height[L],height[R])
tmp = (R-L)*min(height[L],height[R])
ans = max(ans,tmp)
if height[L] < height[R]:
L += 1
else:
R -= 1
return ans
题目链接:15. 三数之和
题目大意:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。注意:答案中不可以包含重复的三元组。
解题思路: 双头指针
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
# 起始条件一
if n<3: return []
# 起始条件二
nums.sort()
ans = list()
for i in range(n):
# 这道题很让人无奈 另外 条件也很不容易记忆
# 细节难点一
# (1) 既然 Sum == 0 那么最小的数大于0 返回结果就Ok!
# (2) 过滤重复元素
if nums[i] > 0 : return ans
if i>0 and nums[i] == nums[i-1]: continue
L,R = i+1,n-1
while L<R:
if nums[i]+nums[L]+nums[R] == 0:
ans.append([nums[i],nums[L],nums[R]])
# 细节难点二
while L<R and nums[L] == nums[L+1] :
L += 1
while L<R and nums[R] == nums[R-1]:
R -= 1
# 细节难点三 注意了 双头指针要往里面 收一收
L,R = L+1,R-1
# 细节难点四
elif nums[i]+nums[L]+nums[R] < 0:
L += 1
else:
R -= 1
return ans
题目链接:16. 最接近的三数之和
题目大意:给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在恰好一个解。
解题思路:
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
n = len(nums)
nums.sort()
ans = 10**7
def update(cur: int)->int:
# 局部变量
nonlocal ans
if abs(cur-target) < abs(ans-target):
ans = cur
for i in range(n):
# 结果子集去重
if i>0 and nums[i]==nums[i-1]:
continue
L,R = i+1,n-1
while L<R:
s = nums[i]+nums[L]+nums[R]
if s == target: return target
update(s)
if s < target:
L += 1
# 去重
while L<R and nums[L]==nums[L+1]: L += 1
else:
R -= 1
while L<R and nums[R]==nums[R-1]: R -= 1
return ans
题目链接:18. 四数之和
题目大意:给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
解题思路:
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
n = len(nums)
nums.sort()
ans = list()
if n<4: return ans
for i in range(n-3):
if i>0 and nums[i]==nums[i-1]: continue
if nums[i]+nums[i+1]+nums[i+2]+nums[i+3] > target:break
if nums[i]+nums[n-1]+nums[n-2]+nums[n-3] < target:continue
for j in range(i+1,n-2):
if j>i+1 and nums[j]==nums[j-1]: continue
if nums[i]+nums[j]+nums[j+1]+nums[j+2] > target:break
if nums[i]+nums[j]+nums[n-2]+nums[n-1] < target:continue
L,R = j+1,n-1
while L<R:
s = nums[i]+nums[j]+nums[L]+nums[R]
if s == target:
ans.append([nums[i],nums[j],nums[L],nums[R]])
while L<R and nums[L]==nums[L+1]: L += 1
while L<R and nums[R]==nums[R-1]: R -= 1
L,R = L+1,R-1
elif s < target:
L += 1
else:
R -= 1
return ans
题目链接:26. 删除有序数组中的重复项
题目大意:给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。将最终结果插入 nums 的前 k 个位置后返回 k 。注意:不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
解题思路:
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
n = len(nums)
low,fast = 1,1
while fast<n:
if nums[fast] != nums[fast-1]:
nums[low]=nums[fast]
low += 1
fast += 1
return low
题目链接:27. 移除元素
题目大意:给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
解题思路:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
n=len(nums)
low,fast = 0,0
while fast<n:
if nums[fast] != val:
nums[low] = nums[fast]
low += 1
fast += 1
return low
题目链接:33. 搜索旋转排序数组
题目大意:整数数组 nums 按升序排列,数组中的值 互不相同 。在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
解题思路:
class Solution:
def search(self, nums: List[int], target: int) -> int:
n = len(nums)
L,R = 0,n-1
while L<=R:
mid = L+(R-L)//2
if nums[mid] == target: return mid
if nums[0] <= nums[mid]:
if nums[0] <= target < nums[mid]:
R = mid-1
else:
L = mid+1
else:
if nums[mid] < target <= nums[n-1]:
L = mid+1
else:
R = mid-1
return -1
题目链接:34. 在排序数组中查找元素的第一个和最后一个位置
题目大意:给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题
解题思路:
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
# 双指针
n = len(nums)
if n == 0 or target not in nums: return [-1,-1]
low,high = 0,n-1
while low<=high:
if nums[low] == target: low = low
else: low += 1
if nums[high] == target: high = high
else: high -= 1
if low >= 0 and high >= 0 and nums[low] == nums[high]:
return [low,high]
break
题目链接:33. 搜索旋转排序数组
题目大意:给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。
解题思路:
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
L,R = 0,len(nums)-1
while L<=R:
mid = L+(R-L)//2
if nums[mid] == target:
return mid
if nums[mid]>target:
R = mid-1
else:
L = mid+1
return L
题目链接:39. 组合总和
题目大意:给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。对于给定的输入,保证和为 target 的不同组合数少于 150 个。
解题思路:
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
def backTrack(start: int,tmp:List[int],target:int) -> None:
for i in range(start,n):
c = candidates[i]
if c == target:
ans.append(tmp+[c])
return
if c < target:
backTrack(i,tmp+[c],target-c)
else:
return
candidates.sort()
n = len(candidates)
ans = []
backTrack(0,[],target)
return ans
题目链接:40. 组合总和 II
题目大意:给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用 一次 。注意:解集不能包含重复的组合。
解题思路:
if i>start and candidates[i-1] == candidates[i]: continue
backTrack(i+1,tmp+[c],target-c)
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
def backTrack(start: int,tmp:List[int],target:int) -> None:
for i in range(start,n):
if i>start and candidates[i-1] == candidates[i]:
continue
c = candidates[i]
if c == target:
ans.append(tmp+[c])
return
if c < target:
backTrack(i+1,tmp+[c],target-c)
else:
return
candidates.sort()
n = len(candidates)
ans = []
backTrack(0,[],target)
return ans
今天,就先到这里,今天涨了几个粉丝,挺开心的!继续加油,明天,读论文,再写点总结。