Day7|Leetcode 454. 四数相加 II Leetcode 383. 赎金信 Leetcode 15. 三数之和 Leetcode18. 四数之和

Leetcode 454 四数相加 II

题目链接 454 四数相加 II

本题目主要考察的还是哈希表中的unordered_map,为什么用map,是因为四个数组没有限制范围,其次需要记录下标和出现的次数,所以只能用map,为什么要用unordered_map,因为本题目对key没有要求有序性,我们将从中选择效率最高的那个,所以只能选择unordered_map。将四个数分成两两相加,这样是时间复杂度最小的情况,下面直接上代码:

class Solution {
public:
    int fourSumCount(vector& nums1, vector& nums2, vector& nums3, vector& nums4) {
            unordered_map umap;//先建立unordered_map:对key无要求有序,且效率高
            int cnt = 0;
            for(int a: nums1){
                for(int b:nums2){
                    umap[a+b]++;//统计次数,同一结果不一定是相同元素带来的
                }
            }
            for(int c:nums3){
                for(int d:nums4){
                   int target = 0-(c+d);//寻找和值为零的目标值
                    if(umap.find(target)!=umap.end()){//若找到
                        cnt+=umap[target];//加上次数即是答案,原理就是组合数
                    }
                }
            }
            return cnt;
    }
};

Leetcode 383 赎金信

题目链接383 赎金信

本题目和前面做过的  有效的字母异位词 很相似,先把magazine中出现过的元素记录下来,这里对record[magazine]的做加法,然后去对比magazine中的元素,对比的过程就是对record[ransomNote]做减法,若record[magazine]= =record[ransomNote],record[ransomNote]就为0,返回true,否则就为负数,为负数就返回false,还有,ransomNote长度>magazine长度

那就返回false

下面上代码和注释:

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26] = {0};
        if(ransomNote.size()>magazine.size()){
            return false;`//ransomNote 不能构成 magazine 里面的字符
        }
        for(int i=0;i

Leetcode 15 三数之和 

题目链接 15 三数之和

本题目实际上有两种方法,一种是哈希法(map),但是考虑去重的地方太多了,所以就不再考虑这个方法,而改用双指针法,先说一下简单的思路,首先对数组中的元素进行一个排序,接着要固定好指针的位置(位置如图所示)

Day7|Leetcode 454. 四数相加 II Leetcode 383. 赎金信 Leetcode 15. 三数之和 Leetcode18. 四数之和_第1张图片

 排序后若nums[i]<0,就不存在三数之和大于0的情况了,除去这种情况,就是正常的双指针移动了,i首先是正常移动,如果三个数之和小于0,就让left右移,使之和增大,如果反之,就让right左移,让之和减小,直到三数之和等于0,就记录一下。但是由于题目要求,不可以包含重复的三元组,所以我们要进行去重操作:

下面就直接上代码加注释(代码中有去重操作的具体解释):

class Solution {
public:
    vector> threeSum(vector& nums) {
        vector> result;
        sort(nums.begin(),nums.end());
        for(int i=0;i0){
                return result;//排序后,数组开头元素大于零,就没无法满足条件
            }
            //明确一点,a动一步之后,left和right不停的移动寻找满足题意的值
            //这里是去重的第一步操作,若i指针指向的元素和之前的i指针指向的元素相同,即重复a;
            //还有一种错误的去重操作:
             /*
            if (nums[i] == nums[i + 1]) {
                continue;
            }
            */
            //本方法就遗漏了-1,-1,2这种情况
            //我们要做的是 不能有重复的三元组,但三元组内的元素是可以重复的。
            if(i>0&&nums[i]==nums[i-1]){
                continue;//所以这里要保证数组下标始终大于0
            }
            int left = i+1;//双指针定位
            int right = nums.size()-1;
            while(right>left){
                if(nums[i]+nums[right]+nums[left]<0){
                    left++;//如果小于0,就增大三数之和
                }else if(nums[i]+nums[right]+nums[left]>0){
                    right--;//如果大于0,就减小三数之和
                }else{//如果等于就记录到result上面
                     result.push_back(vector{nums[i],nums[left],nums[right]}); 
                     //函数将一个新的元素加到vector的最后面,位置为当前最后一个元素的下一个元素,push_back() 在Vector最后添加一个元素(参数为要插入的值)
                    //第二步去重
                    while(right>left&&nums[right]==nums[right-1]){
                                  right--;//如果right和right前一位数组重复就去重
                        }
            while(right>left&&nums[left]==nums[left+1]){
                left++;//同理
            }
            right--; //找到答案,不停的收缩双指针,继续找
            left++;
                }
            }
        }
        return result;//返回result
    }
};

Leetcode18 四数之和

题目链接 18 四数之和

本题目和三数之和的思路是一模一样的,都是运行双指针法,只不过在三数之和的基础上加上了一层for循环,来控制第四个数。

Day7|Leetcode 454. 四数相加 II Leetcode 383. 赎金信 Leetcode 15. 三数之和 Leetcode18. 四数之和_第2张图片

下面直接上代码加注释:

class Solution {
public:
    vector> fourSum(vector& nums, int target) {
        vector> result;//定义储存数组
        sort(nums.begin(),nums.end());//对数组进行排序
        for(int k=0;ktarget&&nums[k]>0&&target>0){//剪枝,由于target不确定(可能为负数),而只有在大于零时才能剪枝
            break;
        }
        if(k>0&&nums[k]==nums[k-1]){//去重操作,前面三数之和解释过了
            continue;
        }
        for(int i=k+1;itarget&&nums[k]+nums[i]>0&&target>0){
                break;//剪枝,和k指针一样的情况
            }
            if(i>k+1&&nums[i]==nums[i-1]){//去重操作
                continue;
            }
            int left = i+1;//定义两指针位置
            int right = nums.size()-1;
            
            while(right>left){
                //这里唯一的不同是
                //多加一个long
                //原因:  nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
                if((long)nums[k]+nums[i]+nums[left]+nums[right]>target){
                    right--;
                }else if((long)nums[k]+nums[i]+nums[left]+nums[right]{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++;
                    }
                    right--;//找到target,双指针不停收缩
                    left++;
                }
            }
        }
       } 
       return result;
    }
};

 end

你可能感兴趣的:(leetcode,哈希算法,算法)