offer52的题目要求是:输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
两数之和
当然,即便输入的不是一个递增排序的数组,我们也可以sort一下变成一个完成排序的数组。数组的递增性给我们带来了许多便利,比如我们可以用双指针从头和结尾开始遍历:
# offer52-solution
class Solution:
def FindNumbersWithSum(self, array, tsum):
if not array:
return []
head = 0
tail = len(array)-1
a = b = tsum
while (head != tail):
if array[head]+array[tail] < tsum:
head = head + 1
elif array[head]+array[tail] > tsum:
tail = tail - 1
else:
if array[head]*array[tail] <= a*b:
a,b = array[head],array[tail]
head = head + 1
if a*b == tsum*tsum:
return []
return [a,b]
三数之和
尽管不是offer52的要求,我们来简单讨论一下三数之和。要求和上述一样:输入一个递增排序的数组,判断数组中是否存在三个数之和为0,若是,输出该三个数。为了简单起见,即便存在多组解,我们只输出一组即可。
其实原题目给出的数组并不是递增的,但是反正我们sort一下夜不费事——排序是为了让元素之间呈现出某种规律,使得后续的处理会简单很多,这就是所谓的没有规律就要创造规律了。题目的要求是三个数之和为0,这样可以方便我们使用正数+负数的技巧。代码我自己没有写,参考:
LintCode三数之和系列问题
# offer52*-solution
# the sum of three nums
class Solution:
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort()
count = len(nums)
collect = []
for i in range(count):
left = i+1
right = count-1
#避免重复找同一个数据
if i >0 and nums[i] == nums[i-1]:
left +=1
continue
#数据按小到大排列,每次选取nums[i],在其后寻找符合a + b + c = 0的两个数据
while left < right:
sum = nums[i] + nums[left] + nums[right]
if sum == 0:
col = [nums[i],nums[left],nums[right]]
collect.append(col)
left+=1
right-=1
#循环中nums[i]已确定,当再确定1个数时,另一个数也确定,左右端任一端出现重复均可跳过
while nums[left] == nums[left-1] and left < right:
left+=1
while nums[right] == nums[right+1] and left < right:
right-=1
if sum<0:
left+=1
elif sum > 0:
right-=1
return collect