python 双指针法_leetcode 两数之和(双指针法)

题目链接:1. 两数之和

做几个小笔记吧:

c++实现哈希可以使用map,查找map里是否含有某个元素时,使用find方法。时间复杂度logN。判断方法:mmp.find(……)!=mmp.end() 或者用mmp.count()!=0 (字典里的元素数量只可能是0或者1)

python实现哈希可以使用字典dict。查找dict里是否有某个元素时,使用get()方法。时间复杂度O1.判断方法:dict.get(……)!=None

class Solution {//两遍哈希

public:

vector twoSum(vector& nums, int target) {

map mmp;

int length=nums.size();

for (int i=0;i

mmp[nums[i]]=i;

}

for(int i=0;i

if( mmp.find(target-nums[i])!=mmp.end() && mmp[target-nums[i]]!=i)

return {i,mmp[target-nums[i]]};

}

return {};

}

};

class Solution {//一遍哈希

public:

vector twoSum(vector& nums, int target) {

mapm;

int length=nums.size();

for(int i=0;i

if(m.find(target-nums[i])!=m.end()) return {m[target-nums[i]],i};//注意返回顺序,下标小的在前面。

m[nums[i]]=i;

}

return {};

}

};

class Solution:

def twoSum(self, nums: List[int], target: int) -> List[int]:

length=len(nums)

mmp={}

for i in range(length):

mmp[nums[i]]=i;

for i in range(length):

if mmp.get(target-nums[i]) and mmp[target-nums[i]]!=i:

return [i,mmp[target-nums[i]]]

return []

以上均不是重点。

重点:双指针法。

我理解的双指针法:

用两个指针,一前一后指向一个有序数组的头和结尾,根据题目的约束条件,头尾指针根据条件分别(只能)头向后、尾向前移动,双指针法能够达到遍历所有可能的情况。

举个例子来讲:

就这个题而言,给了我们一个数组和一个目标数字,要求找到数组中的两个数字(a1,a2)之和等于目标数字(target)。那如何利用双指针法来做呢?首先,我们要对数组排序,假设排好的顺序是从小到大。之后,我们设置两个指针:head、tail,假设它们指向的结点值分别为first、second。那么我们就应该求first+second=target。

设置head=0、tail=length-1。由于我们已经对数组排好序,所以有三种情况:

first+second>target(大于的情况)

first+second

first+second==target (等于的情况)

应对以上三种情况分别有三种对策:

while(情况1){second-=1;}

while(情况2){first+=1;}

return ans;

证明(最重要):

理解了这个证明,也就明白了这种情况下的双指针法。

数组里的数字:a1,a2…………an单增(单调不降)。

对于每一个head,它对应的数字first,如果和tail对应的数字second能够有:first+second==target的话,那即使在一开始first+second>target的情况下,随着tail的递减,相等的这个结果也不会被跳过。所以如果出现了小于的情况那对于当前的head肯定是不可能有等于的情况能够出现(因为tail使递减的)。

所以,对于当前的tail,head如果不变,那tail取右边的值则结果为大于的情况;tail取自身以及左边的值结果则为小于的情况。

所以,head只能加一。因为如果减一那肯定得到的情况是小于。

出现小于的情况时,tail能不能+1而不是head+1呢?显然不能呀,因为上一轮的tail-1就是因为和的结果为大于的情况。tail再+1不就又回去了么。。。。

设这时head=i、tail=j。 这样我们就已经证明了first属于[0,i]与second[j,length-1]对应的值,first+second不可能产生target。

不会用数学语言描述,证明写得一塌糊涂。

就这个题来讲,贴一个错误的代码吧,如果题目要求是让返回数组值那不会有错,但是让返回数组下标。。。。

因为排了个序,所以数组下标乱了。就用map保存下标。

但是map,同样的键只能保存一个值。所以,当数组中有多个值相同,且它们的和为答案的时候,就没法返回正确的下标了。

找键用的双指针法实现的。

class Solution {

public:

vector twoSum(vector& nums, int target) {

int length=nums.size();

int left=0,right=length-1;

//存下标

map m;

for(int i=0;i

m[nums[i]]=i;

}

sort(nums.begin(),nums.end());

while(left

if(nums[left]+nums[right]

else if(nums[left]+nums[right]>target) right--;

else {

vector ans;

if(m[nums[left]]

ans={m[nums[left]],m[nums[right]]};//vector初始化的一种方法。

}else{

ans={m[nums[right]],m[nums[left]]};

}

return ans;

}

}

return {};

}

};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值