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<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
            unordered_map<int ,int> 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<magazine.length();i++){
            record[magazine[i]-'a']++;
            // 通过record数据记录 magazine里各个字符出现次数
            
        }
        for(int j=0;j<ransomNote.length();j++){
            record[ransomNote[j]-'a']--;
             // 遍历ransomNote,在record里对应的字符个数做--操作
            if(record[ransomNote[j]-'a']<0){// 如果小于零说明ransomNote里出现的字符,magazine没有
                return false;
            }
        }
        return true;
        
    }
};

Leetcode 15 三数之和 

题目链接 15 三数之和

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

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

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

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size();i++){
            if(nums[i]>0){
                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<int>{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循环,来控制第四个数。

下面直接上代码加注释:

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++){//多加一层循环
            if(nums[k]>target&&nums[k]>0&&target>0){//剪枝,由于target不确定(可能为负数),而只有在大于零时才能剪枝
            break;
        }
        if(k>0&&nums[k]==nums[k-1]){//去重操作,前面三数之和解释过了
            continue;
        }
        for(int i=k+1;i<nums.size();i++ ){//这里i要在k的下一位
            if(nums[k]+nums[i]>target&&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]<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++;
                    }
                    right--;//找到target,双指针不停收缩
                    left++;
                }
            }
        }
       } 
       return result;
    }
};

 end

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值