两数、三数之和问题

两数之和

在这里插入图片描述

双指针

两数之和问题显而意见是用双指针来写,要想使用双指针前提是数组提前有序。这道题的坑就在这里,数组无序,我们需要先排序,但是题目让返回的却是数字所在原数组的下标,如果已排序就乱了,因此有两种方法,一种就是我认为简单的我们在进行排序,只不过把下标和数组放在一起进行排序。

#include<bits/stdc++.h>
int vis[100100];
//这里的默认为是大于号
bool cmp(pair<int,int>a, pair<int,int> b)
{
    if(a.first!=b.first)
    {
        return a.first<b.first;
    }
    else {
        return a.second<b.second;
    }
}

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
    	
    	int l=0;
		int r=nums.size()-1;
        vector<pair<int,int> > num;
        for(int i=0;i<nums.size();i++)
        {
            num.push_back(make_pair(nums[i],i));
        }

        sort(num.begin(),num.end(),cmp);

        vector<int> v;
		
		while(l<r)
		{
            pair<int,int> t1=num[l];
            pair<int ,int> t2=num[r];

			if(t1.first+t2.first==target) 
			{
				v.push_back(t1.second);
				v.push_back(t2.second);
				break;
			}
			else if(t1.first+t2.first>target)
			{
				r--;
			}
			else l++;			
		} 
		return v;
    }
};

hash表

先遍历一遍数组,将数组中的元素和下标存放于一个无序的哈希表中,其中数组中的元素为key,下标为value。
遍历一遍数组,利用 map的 find函数查找哈希表中是否存在 (target-当前元素的值)。 注意可能出现 target = 2numbers[i]这种情况,所以if条件判断内要 && m[target-numbers[i]] != i。 最后返回符合条件两个下标即可。


class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) 
    {
        map<int, int> m;
        int n = numbers.size();
		
		//这一步比较巧妙,如果是target=2*x的时候
		//map存放的是第二次的下标,以为第一次我们会遍历到。
        for(int i=0; i<n; i++)
            m[numbers[i]] = i;

        for(int i=0; i<n; i++)
        {
            if(m.find(target-numbers[i]) != m.end() && m[target-numbers[i]] != i)
            {
                return {i+1, m[target-numbers[i]]+1};
            }
        }
        return {};
    }
};

三数之和

在这里插入图片描述这道题的坑在于要去重,最暴力的写法就是三层for循环,第一层,第二层for循环去一下重。为什么第三层不需要去重呢,因为如果第一层和第二层的不相同了,第三层的也肯定不相同。暴力写法时间复杂度太高了,因此我们想到了里面两层使用双指针的方法进行优化,时间复杂度就变成了O(n^2)级别的了。

这道题目让求得就是数字,而不是下标,排序没什么影响。


#include<bits/stdc++.h>
class Solution {
public:
    vector<vector<int> > threeSum(vector<int>& nums) {
    	
    	sort(nums.begin(),nums.end());
    
    	
    	vector<vector<int> > v; 
    	
    	for(int i=0;i<nums.size();i++)
    	{
    		
    	//	第一个数去重 
    		if(i>0&&nums[i]==nums[i-1]) continue;
    		
    		int l=i+1;
    		int r=nums.size()-1;
    		
    		while(l<r)
    		{
    		//	第二个数去重 
    			if(l>i+1&&nums[l]==nums[l-1])
    			{
    				l++;
    				continue;
				}
				
				if(nums[i]+nums[l]+nums[r]==0)
				{
					v.push_back({nums[i],nums[l],nums[r]});
					l++;
					r--;
				}
                else if(nums[i]+nums[l]+nums[r]>0)
                {
                    r--;
                }
                else l++;
			}
    
		}
		
		return v;

    }
};

最接近的三数之和

在这里插入图片描述这道题就是在找三数之和或等于的情况下多一步更新最接近值,其余的完全一样。

class Solution {
public:

    int best=100000000;
    int update(int sum,int target)
    {
        if(abs(best-target)<abs(sum-target)) return best;
        return sum;
    }

    int threeSumClosest(vector<int>& nums, int target) {

        sort(nums.begin(),nums.end());
       	
    	for(int i=0;i<nums.size();i++)
    	{
    		
    	//	第一个数去重 
    		if(i>0&&nums[i]==nums[i-1]) continue;
    		
    		int l=i+1;
    		int r=nums.size()-1;
    		
    		while(l<r)
    		{
    		//	第二个数去重 
    			if(l>i+1&&nums[l]==nums[l-1])
    			{
    				l++;
    				continue;
				}

                best=update(nums[i]+nums[l]+nums[r],target);
				
				if(nums[i]+nums[l]+nums[r]==target)
				{
					return target;
				}
                else if(nums[i]+nums[l]+nums[r]>target)
                {
                    r--;
                }
                else l++;
			}   
		}		
		return best;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值