zoukankan      html  css  js  c++  java
  • 几数之和的题目

    总结:

    两数之和——哈希表:时间复杂度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;
        }
    };
  • 相关阅读:
    切片
    docker基础
    第18课 脚本练习二(找出文件下最大文件)
    第17课 脚本练习一(添加新用户)
    第十四课 脚本编程(重定向+变量)
    第十课 新建共享文件夹
    第九课 Linux文本处理
    第八课 正则表达式
    第七课 VI全屏文本编辑器
    第六课 Linux文件系统文本操作命令
  • 原文地址:https://www.cnblogs.com/masbay/p/14098900.html
Copyright © 2011-2022 走看看