前言:出差途中刷一题,总结一下思路。
题目描述:
输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。
思路总结:刚看这道题的时候,注意题目几个关键信息,递增序列,查找,和为s,输出乘积最小。首先想到的是确定判断边界,要素s小于最第一个数的两倍或者s大于最后数的两倍,那么就不可能有解。或者输入数组是空集,那么也不可能有解。其次就是如何找到这个相加和为s的两个数了。我的思路是找到s/2在数列中的位置a以及下角标,再将数组以此分两部分,左边小于s/2,右边大于s/2。有想设置两个指针从中间分别向左和右移动,看其和是不是等于s。但是感觉太复杂,后来就用一个指针,从位置a向右移动到k值,再利用数组的特性,找到s-k的值。将所有找到的值存入列表中,那么结果中只需要返回最后一组数据就行。这个方法能顺利通过,但是不是最好的。(有想到二叉树的特性)
再深入题目的意思,要想两个值的积最小,那必然是头尾相差最大的两个数。同样的夹击的思路,从中间夹击不如从两边用两个移动的指针夹击,这样找到的第一个组解就是满足题目的解。根本不需要找到所有的解来判断乘积最小了。不需要太复杂的代码,主要是分析清楚题目的意思,理清逻辑关系。有些题目设计用数据结构,有些题目就是好好考虑潜在的数学特性,不一而足。
我的代码:(27s。5728k)
# -*- coding:utf-8 -*-
class Solution:
def FindNumbersWithSum(self, array, tsum):
# write code here
#这道题有很强的数学性。
if not array: #判断是不是数组
return array #返回数组。如果是[],则返回[]
n=len(array) #数组长度
num,j=0,0
res=[]
if tsum<array[0] or tsum>2*array[n-1]: #边界条件
return 0
for i in range(n):
if array[i]<=tsum/2:
num+=1 #找到中间值的位置
while num+j<n: #下标应该小于n,一个指针开始查找/
for number in array: #@判断条件
if number==tsum-array[num+j]:
res.append([number,array[num+j]])#将所有查找的两个数以一个数组的形式append进数组。
j+=1
if len(res)>0: #判断结果存在否。
return res[-1]
else:
return res
更新后的代码。(两边夹击 31s 5736k)
# -*- coding:utf-8 -*-
class Solution:
def FindNumbersWithSum(self, array, tsum):
# write code here
#这道题有很强的数学性。
if not array: #判断是不是数组
return array #返回数组。如果是[],则返回[]
n=len(array) #数组长度
i,j=0,n-1
result=[]
if tsum<array[0] or tsum>2*array[n-1]: #边界条件
return 0
while i<j:
if array[i]+array[j]>tsum:
j-=1
elif array[i]+array[j]<tsum:
i+=1
else:
result.append([array[i],array[j]])
break
if len(result)==0:
return result
else:
return result[0]
总结:两种解法对比,我的思路居然时间要短一些。有点类似于二分查找速度要快一些啊。重点掌握指针如何移动的操作以及break的用法。