本篇为Datawhale组队学习计划第21期LeetCode精选题目组Task04学习笔记。
初学,时间有点仓促,很多解法没有详细分析,未来会修改,见谅。
所有题目均参考了Datawhale学习文档,开源地址:
https://github.com/datawhalechina/team-learning-program/tree/master/LeetCodeTencent
016 最接近的三数之和
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
思路
类似昨天的015三数之和,依然采用【排序+双指针】的解法。
假设确定了枚举的第一个数a,那么剩余两数的和需要尽量接近target-a。为了避免循环,我们先对数组进行排序(不妨按升序):
假设数组的长度为n,我们先枚举a,它在数组中的位置为i;
为了防止重复枚举,我们在位置 [i+1,n) 的范围内枚举b和c。
借助双指针,我们就可以对枚举的过程进行优化。分析过程类似上次011的长短板。
我们用 pb和 pc分别表示指向b,c的指针,初始时,pb指向位置i+1,即左边界,pc指向位置n−1即右边界。在每一步枚举的过程中,我们用 a+b+c来更新答案,并且:
如果 a+b+c ≥ target那么就将pc向左移动一个位置;
如果 a+b+c <t arget那么就将pb向右移动一个位置。
实际上,pb和pc就表示了我们当前可以选择的数的范围,而每一次枚举的过程中,我们尝试边界上的两个元素,根据它们与 target的值的关系,选择「抛弃」左边界的元素还是右边界的元素,从而减少了枚举的范围。这种思路与 11. 盛最多水的容器 中的双指针解法也是类似的。
Python实现
代码及注释来自官方题解,题解中也提到了其他的小优化。
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
nums.sort()
n = len(nums)
best = 10**7
# 根据差值的绝对值来更新答案
def update(cur):
nonlocal best
if abs(cur - target) < abs(best - target):
best = cur
# 枚举 a
for i in range(n):
# 保证和上一次枚举的元素不相等
if i > 0 and nums[i] == nums[i - 1]:
continue
# 使用双指针枚举 b 和 c
j, k = i + 1, n - 1
while j < k:
s = nums[i] + nums[j] + nums[k]
# 如果和为 target 直接返回答案
if s == target:
return target
update(s)
if s > target:
# 如果和大于 target,移动 c 对应的指针
k0 = k - 1
# 移动到下一个不相等的元素
while j < k0 and nums[k0] == nums[k]:
k0 -= 1
k = k0
else:
# 如果和小于 target,移动 b 对应的指针
j0 = j + 1
# 移动到下一个不相等的元素
while j0 < k and nums[j0] == nums[j]:
j0 += 1
j = j0
return best
#作者:LeetCode-Solution
#链接:https://leetcode-cn.com/problems/3sum-closest/solution/zui-jie-jin-de-san-shu-zhi-he-by-leetcode-solution/
#来源:力扣(LeetCode)
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
020 有效的括号
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-parentheses
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例:
输入: “()”
输出: true
输入: “()[]{}”
输出: true
输入: “(]”
输出: false
输入: “([)]”
输出: false
输入: “{[]}”
输出: true
思路
比较常见(和相对简单)的一道题,考察【栈】。官方题解
判断括号的有效性可以使用「栈」这一数据结构来解决。
我们对给定的字符串s进行遍历,当我们遇到一个左括号时,我们会期望在后续的遍历中,有一个相同类型的右括号将其闭合。由于后遇到的左括号要先闭合,因此我们可以将这个左括号放入栈顶。
当我们遇到一个右括号时,我们需要将一个相同类型的左括号闭合。此时,我们可以取出栈顶的左括号并判断它们是否是相同类型的括号。如果不是相同的类型,或者栈中并没有左括号,那么字符串s无效,返回False。为了快速判断括号的类型,我们可以使用哈希映射(HashMap)存储每一种括号。哈希映射的键为右括号,值为相同类型的左括号。
在遍历结束后,如果栈中没有左括号,说明我们将字符串s中的所有左括号闭合,返回True,否则返回False。
其他优化:
注意到有效字符串的长度一定为偶数,因此如果字符串的长度为奇数,我们可以直接返回False,省去后续的遍历判断过程。
Python实现
class Solution:
def isValid(self, s: str) -> bool:
if len(s) % 2 == 1:
return False
pairs = {
")": "(",
"]": "[",
"}": "{",
}
stack = list()
for ch in s:
if ch in pairs:
if not stack or stack[-1] != pairs[ch]:
return False
stack.pop()
else:
stack.append(ch)
return not stack
#作者:LeetCode-Solution
#链接:https://leetcode-cn.com/problems/valid-parentheses/solution/you-xiao-de-gua-hao-by-leetcode-solution/
#来源:力扣(LeetCode)
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
021 合并两个有序链表
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 :
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
输入:l1 = [], l2 = []
输出:[]
输入:l1 = [], l2 = [0]
输出:[0]
提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列
思路
这里我们用递归,官解里也讲述了迭代的方法。
我们可以如下递归地定义两个链表里的 merge 操作(忽略边界情况,比如空链表等):
list1[0] + merge(list1[1:],list2) ( if list1[0] < list2[0] )
list2[0] + merge(list1,list2[1:]) ( otherwise)
也就是说,两个链表头部值较小的一个节点与剩下元素的 merge 操作结果合并。
算法
我们直接将以上递归过程建模,同时需要考虑边界情况。
如果 l1 或者 l2 一开始就是空链表 ,那么没有任何操作需要合并,所以我们只需要返回非空链表。否则,我们要判断 l1 和 l2 哪一个链表的头节点的值更小,然后递归地决定下一个添加到结果里的节点。如果两个链表有一个为空,递归结束。
Python实现
class Solution:
def mergeTwoLists(self, l1, l2):
if l1 is None: # 判断是否为空/结束
return l2
elif l2 is None:
return l1
elif l1.val < l2.val:
# 递归,将较小节点与剩下元素的操作合并
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
#作者:LeetCode-Solution
#链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode-solu/
#来源:力扣(LeetCode)
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。