力扣学习笔记 day4

题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值。

  1. 首先根据提示,数组长度大于三,省去了长度的判断;确保有唯一解,说明三个数的组合唯一,相较于15题可以省去遍历时跳过重复值的操作。
  2. 对第一个数进行遍历,三数之和sum尽量接近目标值即可理解为sum-target的值逼近0。
  3. 用双指针分别指向第二、三个数,从剩余数组的头尾向中间靠近,直至两数相遇
    • 若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.有效的括号(简单)


题意

给定一个包含小括号、中括号、大括号的字符串,判断其是否满足:

  • 左括号必须用同类型右括号闭合
  • 左括号必须以正确的顺序闭合
    • “{}()[]” ✅
    • “}{)(][” ❎

解题

本题思路比较简单,考虑左右括号的闭合,使用栈来遍历字符串无疑是最好的选择,具体做法是:

  1. 建立一个字典,将左右括号分别作为键和值存储进去。
  2. 遍历字符串,对于遍历到的字符串
    • 如果是左括号,存储到栈中
    • 如果是右括号,判断栈顶元素是否为对应的左括号,如果是,满足要求,栈顶元素弹出;如果不是,返回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的长度

扫描二维码关注公众号,回复: 12257279 查看本文章

而后参考题解,还可以使用 递归 的方法,思路和上面类似,就是每次比较两个链表的第一位,把更小的作为结果输出的第一项。把去除第一项的链表作为新链表与另一条继续比较。

具体实现如下:

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)

猜你喜欢

转载自blog.csdn.net/piaoyikang3268/article/details/112687828
今日推荐