题016.最接近的三数之和(中等)
题意
给定一个包含n个整数的数组nums和一个目标值target,找出nums中和与target最接近的三个数,返回三数之和。(假设有唯一答案,数组长度大于3)
eg
输入: nums=[-1,2,1,-4],target=1
输出: 2
解释: 与target最接近的和是2 (-1+2+1)
解题
本题和第15题(三数之和为0)很像,所以我参照上次解15题的方式,尝试用双指针法来求三数之和,逼近target值。
- 首先根据提示,数组长度大于三,省去了长度的判断;确保有唯一解,说明三个数的组合唯一,相较于15题可以省去遍历时跳过重复值的操作。
- 对第一个数进行遍历,三数之和sum尽量接近目标值即可理解为sum-target的值逼近0。
- 用双指针分别指向第二、三个数,从剩余数组的头尾向中间靠近,直至两数相遇
- 若sum-target>0,将第三个数左移
- 若sum-target<0,将第二个数右移
- 若差值为0,说明存在和为target的三个数,直接跳出循环,返回target值
复杂度分析
- 数组排序的时间复杂度为O(nlogn)
- 遍历的时间复杂度为O( n 2 n^2 n2),第一个数的遍历为O(n),双指针为O(n)
- 总的时间复杂度为O(nlogn)+O( n 2 n^2 n2)=O( n 2 n^2 n2)
代码
def threesumClosest(self,nums:List[int],target:int)->int:
ln=len(nums)
nums.sort()
cm=float('inf')
sum=0
for i in range(ln):
tmp=-target+nums[i]
j,k=i+1,ln-1
while j<k:
cur=tmp+nums[k]+nums[j]
if cur==0:
return target
#若差值的绝对值更小,则更新当前比较值
if cm>abs(cur):
cm=abs(cur)
sum=nums[i]+nums[j]+nums[k]
if cur<0:
j+=1
else:
k-=1
return sum
题020.有效的括号(简单)
题意
给定一个包含小括号、中括号、大括号的字符串,判断其是否满足:
- 左括号必须用同类型右括号闭合
- 左括号必须以正确的顺序闭合
- “{}()[]” ✅
- “}{)(][” ❎
解题
本题思路比较简单,考虑左右括号的闭合,使用栈来遍历字符串无疑是最好的选择,具体做法是:
- 建立一个字典,将左右括号分别作为键和值存储进去。
- 遍历字符串,对于遍历到的字符串
- 如果是左括号,存储到栈中
- 如果是右括号,判断栈顶元素是否为对应的左括号,如果是,满足要求,栈顶元素弹出;如果不是,返回False
经历了一次遍历,所以时间复杂度为O(n)
代码
def isValid(self,s:str)->bool:
dic={"{":"}","[":"]","(":")"}
m=["?"] #为了避免栈为空时pop操作出错,给栈底填个其他符号
for i in s:
if i in dic.keys():
m.append(i)
elif dic[m.pop()]!=i:
return False
return len(m)==1 #若栈中只剩一个问号,说明遍历完成且未出错
题021.合并两个有序链表
题意
将两个升序链表合并为一个并且输出
eg.
输入: l1 = [1,2,4], l2 = [1,3,4]
输出: [1,1,2,3,4,4]
解题
马上想到的方法就是两两比较,新建一个链表,然后遍历l1和l2,哪个节点的值小就加到新链表的后面,直至l1或者l2遍历结束。
这样的做法比较简单,直接贴代码
a=b=ListNode(None)
while l1 and l2:
if l1.val<l2.val:
b.next=l1
l1=l1.next
else:
b.next=l2
l2=l2.next
b=b.next
#哪个链表更长,就把它未遍历的部分接到新链表的后面
if l1:
b.next=l1
else:
b.next=l2
return a
这样做经历了一次遍历,时间复杂度为O(m+n),m,n分别为l1,l2的长度
而后参考题解,还可以使用 递归 的方法,思路和上面类似,就是每次比较两个链表的第一位,把更小的作为结果输出的第一项。把去除第一项的链表作为新链表与另一条继续比较。
具体实现如下:
def merge(self,l1,l2):
#首先设置递归终止条件
if not l1: return l2
if not l2: return l1
if l1.val<l2.val:
l1.next=self.merge(l1.next,l2)
return l1
else:
l2.next=self.merge(l1,l2.next)
return l2
时间复杂度依然为O(m+n)