剑指offer刷题
11. 两数之和 II - 输入有序数组
题目要求
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
解题思路
采用双指针的方式最简单,时间复杂度为O(n)。
代码
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
i, j = 0, len(numbers) - 1
while i < j:
sum_num = numbers[i] + numbers[j]
if sum_num == target:
return [i+1, j+1]
elif sum_num < target:
i += 1
elif sum_num > target:
j -= 1
12.两数之和 III - 数据结构设计
题目要求
设计一个接收整数流的数据结构,该数据结构支持检查是否存在两数之和等于特定值。
实现 TwoSum 类:
TwoSum() 使用空数组初始化 TwoSum 对象
void add(int number) 向数据结构添加一个数 number
boolean find(int value) 寻找数据结构中是否存在一对整数,使得两数之和与给定的值相等。如果存在,返回 true ;否则,返回 false 。
加上一个示例可能会更好理解。
解题思路
这道题比较特殊,笔者是第一次遇到。先借鉴一下大佬们的解法。
注意:这里的self类似于js的this,一定要有这个,不然程序不知道你指代的是什么。
上述思路比较巧妙的一点是,用输入的值作为字典的key,而出现的次数作为字典的value。这两种情况也是很巧的,若两个数相加为value时(所要找的值,而非字典的value),要么它们的次数是至少为1,要么一定大于1。
比如,value=4,若2出现了两次,它们的Key相等,但它们在字典中的次数一定是有一个大于1的。若是【1,3】,它们出现的次数可以一样,也可以不一样,但是至少是出现一次的,不可能是0。
代码
class TwoSum:
def __init__(self):
"""
Initialize your data structure here.
"""
self.numbers = {}
def add(self, number: int) -> None:
"""
Add the number to an internal data structure..
"""
if number not in self.numbers:
self.numbers[number] = 1
else:
self.numbers[number] += 1
def find(self, value: int) -> bool:
"""
Find if there exists any pair of numbers which sum is equal to the value.
"""
for key in self.numbers:
key2 = value - key
if key2 in self.numbers:
if self.numbers[key2] >= 1 and key != key2:
return True
elif self.numbers[key2] > 1 and key == key2:
return True
return False
# Your TwoSum object will be instantiated and called as such:
# obj = TwoSum()
# obj.add(number)
# param_2 = obj.find(value)
13.两数之和 IV - 输入 BST
题目要求
解题思路
解法一:中序遍历法,先把给定的数存入一个列表中,然后使用双指针来判断两者的和是否等于k值。(后面的部分类似于上面的解法)
解法二:非中序遍历法。这是从其他大佬那里借鉴来的方法,即直接按节点及其左右子节点搜索的方法。由于题目给定了一棵二叉树,就不像之前的题目可能会出现同样的数字,所以本题就可以使用集合set()。 本解法是直接对所有节点进行搜索,即若所有节点值都在字典中,就返回True,若没有则继续搜索当前节点的左右子节点,直到找到所有符合的值。
解法二的方法速度果然快很多,因为不用多次对比,而直接顺着树进行搜索。
代码
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def findTarget(self, root: TreeNode, k: int) -> bool:
# 解法一:中序遍历法
nums = []
def mid_order(root):
if root:# 要判断root是否存在,不存在则直接返回false
mid_order(root.left)
nums.append(root.val)
mid_order(root.right)
mid_order(root)
i, j = 0, len(nums) - 1
while i < j:
if nums[i] + nums[j] == k:
return True
elif nums[i] + nums[j] > k:
j -= 1
else:
i += 1
return False
# 解法二:直接按节点及左右子节点搜索法
self.comp = set() #用set保存已经出现过数的互补数,若一旦出现互补数,则本体已经出现过!!
def find(root):
if not root:
return False
if root.val in self.comp:
return True
else:
self.comp.add(k - root.val)
return find(root.left) or find(root.right)
return find(root)
解法一:
解法二:
14.三数之和
题目要求
给你一个包含 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)
res=[]
if(not nums or n<3):
return []
nums.sort()
res=[]
for i in range(n):
if(nums[i]>0):
return res
if(i>0 and nums[i]==nums[i-1]):
continue
L=i+1
R=n-1
while(L<R):
if(nums[i]+nums[L]+nums[R]==0):
res.append([nums[i],nums[L],nums[R]])
while(L<R and nums[L]==nums[L+1]):
L=L+1
while(L<R and nums[R]==nums[R-1]):
R=R-1
L=L+1
R=R-1
elif(nums[i]+nums[L]+nums[R]>0):
R=R-1
else:
L=L+1
return res