几数之和的题目

总结:

两数之和——哈希表:时间复杂度O(n),暴力解法O(n^2)

三数之和——双指针:一层i的for循环,双指针left和right。时间复杂度O(n^2),暴力解法O(n^3)

四数之后——双指针:两层i和k的for循环,双指针left和right,时间复杂度O(n^3),暴力解法O(n^4)

再增加也是一样的,三个、四个甚至更多数之和都是这个方法,代码也是差不多,思路都一样的,有几个小地方需要注意:(1)给的数组一定要进行排序;(2)每个下标的数字都要进行去重,循环里头的去重和双指针的left和right去重,去重基本都是当前位和前一位去比较,不能当前位和下一位比较,别的倒也是没啥了,细心一点就能写对。

四数相加II那道题不太一样,要求不一样,这个更为简单一些。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map <int,int> map;//不需要有序,所以用这个
        for(int i = 0; i < nums.size(); i++) {
            auto iter = map.find(target - nums[i]);//find函数返回的是迭代器
            if(iter != map.end()) {//这句话表示找到了target-nums[i]这个元素
                return {iter->second, i};//返回找到的元素的下标,还有i这个下标
                
            }
            map.insert(nums[i], i);//如果没找到,不存在里头的话就添加进行
        }
        return {};
    }
};
//这道题还有变体,要是说给你一个数组,让你在里头找所有两个数之和等于target的元组,那就跟三数之和四数之后一样了,双指针法解决,注意去重。

以上这个写法理论上没错,但是力扣报错,不知道为什么,下面的写法更容易理解

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> map;
        // 先将元素放到哈希表里面去
        for (int i = 0; i < nums.size(); i++) {
            map.insert(make_pair(nums[i], i));
        }
        // 下面开始判断是否存在
        for (int i = 0; i < nums.size(); i++) {
            int another = target - nums[i];
            auto iter = map.find(another);
            if (iter != map.end() && iter->second != i) {
                return {i, iter->second};
            }
        }
        return {};
    }
};

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        //这道题如果使用哈希表解决的话,去重会非常的麻烦,所以最好是采用双指针解法
        //先对数组排序,判断特殊情况,过程中要注意去重操作,特别是去重的位置,时机不对都会漏掉情况
        vector<vector<int>> result;//定义二维数组容器
        sort(nums.begin(), nums.end());
        //找出a+b+c = 0
        //a=nums[i], b=nums[left], c=nums[right]
        for(int i=0; i<nums.size(); i++) {
            //特殊情况,排序之后如果第一个元素都大于0了,那就不能存在了
            if(nums[i] > 0)
                return result;
            //去重,这里一定要注意,不能是i和i+1进行比较去重,否则会漏掉-1,-1,2这种情况。
            if(i>0 && nums[i]==nums[i-1])
                continue;

            int left = i+1;
            int right = nums.size()-1;
            while(right > left) {
                if(nums[i]+nums[left]+nums[right] > 0)
                    right--;
                else if(nums[i]+nums[left]+nums[right] < 0)
                    left++;
                else {
                    result.push_back(vector<int>{nums[i], nums[left], nums[right]});//将这个结果放到二维数组中
                    //去重逻辑
                    while(right>left && nums[right]==nums[right-1])
                        right--;
                    while(right>left && nums[left]==nums[left+1])
                        left++;

                    //找到答案,双指针同时收缩,因为是排序的数组
                    right--;
                    left++;
                }
            }
        }
        return result;
    }
};

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        for(int k=0; k<nums.size(); k++) {
            //肯定要对k这这个最前面的元素进行去重,但不能是i和i+1,否则会漏掉情况
            if(k>0 && nums[k]==nums[k-1])
                continue;
            for(int i=k+1; i<nums.size(); i++) {
                //对i也要进行去重,同上
                if(i>k+1 && nums[i]==nums[i-1])
                    continue;
                int left = i+1;
                int right = nums.size()-1;
                while(right>left)
                {
                    if(nums[k]+nums[i]+nums[left]+nums[right] > target)
                        right--;
                    else if(nums[k]+nums[i]+nums[left]+nums[right] < target)
                        left++;
                    else {
                        result.push_back(vector<int>{nums[k],nums[i],nums[left],nums[right]});
                        //去重逻辑
                        while(right>left && nums[right]==nums[right-1])
                            right--;
                        while(right>left && nums[left]==nums[left+1])
                            left++;
                        //找到了一组值,left和right同步缩进
                        right--;
                        left++;
                    }

                }
            }
        }
        return result;
    }
};

class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        //本题的思路可以是:
        //利用哈希表,先统计a+b的值,把值作为map的key,出现的次数作为value,
        //然后遍历c和d,如果在map中找到了0-(c+d)的值,就把个数+1,直到最后
        unordered_map<int, int> umap;
        for(int a : A) {
            for(int b : B) {
                umap[a+b]++;
            }
        }
        int count = 0;
        for(int c : C) {
            for(int d : D) {
                if(umap.find(0-(c+d)) != umap.end())
                    count += umap[0-(c+d)];
            }
        }
        return count;
    }
};

 

posted @ 2020-12-07 19:11  不妨不妨,来日方长  阅读(259)  评论(0编辑  收藏  举报