LeetCode/两数之和

给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标

思路:求两数和等于目标值,首先考虑二重循环暴力求解,分别将每一个数与所有数进行求和匹配,时间复杂度为O(n2)。进一步可以考虑两求和数一个值大于目标值一半,一个值小于一半,可以分割成两部分进行匹配。若能使用C++容器模板,考虑使用哈希表hash_map进一步降低二重循环里匹配所需时间。

1. 暴力求解

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        for(int i=0;i<nums.size();i++)
            for(int j=i+1;j<nums.size();j++)
                if(nums[i]+nums[j]==target) return {i,j};
        return {};
    }
};

2. 哈希表优化

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        map<int,int> m;//建立值和索引哈希表
        for(int i=0;i<nums.size();i++)//从前往后遍历,哈希表的扩大,以及查询匹配值
        {
            if(m.find(target-nums[i])!=m.end())//匹配的值存在哈希表中
                return {m[target-nums[i]],i};
            m[nums[i]]=i;//值为键来获取位置,维护扩大一个哈希表用于查询
        }
        return {};
    };
};

3. 三数之和

先排序,即方便跳过相同的数,也便于双指针的移动,再使用双指针求两数之和

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        // 先枚举 a ,再枚举b,这种遍历的结构注定不会重复,得到其组合数
        for (int first = 0; first < n; ++first) {
            // 需要和上一次枚举的数不相同
            if (first > 0 && nums[first] == nums[first - 1]) //移动到不重复的位置
                continue;
            // c 对应的指针初始指向数组的最右端
            int third = n - 1;
            int target = -nums[first];//目标和,将问题转换为两数之和
            // 枚举 b
            for (int second = first + 1; second < n; ++second) {
                // 需要和上一次枚举的数不相同
                if (second > first + 1 && nums[second] == nums[second - 1])//移动到不重复位置
                    continue;
                // 需要保证 b 的指针在 c 的指针的左侧,左右指针交替移动,这里移动右指针
                while (second < third && nums[second] + nums[third] > target) //和大于目标值
                    --third; //移动右指针
   
                if (second == third)  break;//两指针会和遍历结束,其实循环用while的话不用加这句
                if (nums[second] + nums[third] == target) {//找到目标值的话存入结果
                    ans.push_back({nums[first], nums[second], nums[third]});
                }
            }
        }
        return ans;
    }
};

4. 四数之和

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        int n =nums.size();
        if(n<4) return {};
        sort(nums.begin(),nums.end());
        vector<vector<int>> res;
        long sum;//求和值
        for(int first =0;first<=n-4;first++){//首指针循环
            if(first>0&&nums[first]==nums[first-1]) continue;//跳过重复元素
             for(int second = first + 1;second <= n-3; second++){
                if(second>first+1&&nums[second]==nums[second-1]) continue;//跳过重复元素
                int third = second+1;
                int fouth = n-1;
                while(third<fouth){//最后一重双指针循环
                sum = (long)nums[first]+nums[second]+nums[third]+nums[fouth];
                if(sum==target){
                    res.push_back({nums[first],nums[second],nums[third],nums[fouth]});
                    while(nums[third+1]==nums[third]&&third+1<fouth) third++;
                    while(nums[fouth-1]==nums[fouth]&&third<fouth-1) fouth--;
                    third++;//这里进行扰动,先移动左右指针都可以
                }
                else if(sum<target) third++;
                else if(sum>target) fouth--;
                }
             }
        }   
        return res;
    }
};
posted @ 2022-05-07 21:50  失控D大白兔  阅读(55)  评论(0)    收藏  举报