第六天|454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和

第六天|454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和

454.四数相加II

第454题.四数相加II | 代码随想录

学透哈希表,map使用有技巧!LeetCode:454.四数相加II_哔哩哔哩_bilibili

笔记

通过单独遍历两个数组来提高时间效率

  1. 首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数。
  2. 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
  3. 定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
  4. 再遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
  5. 最后返回统计值 count 就可以了

实操出现问题

为什么我的代码时间非常长?

代码/比较

我的代码:

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        //遍历前两个和后两个数组  1234
        int n=nums1.size();
        int sum12=0;//数组1 和 2 的元素和,放进map里面
        unordered_map<int,int> m_map;//map的key存放和,value存放出现次数
        for(int i=0;i<n;i++)//数组1和2,把他们的和放进一个map里面,map的key存放和,value存放出现次数
        {
            for(int j=0;j<n;j++)
            {
                sum12=nums1[i]+nums2[j];
                if(m_map.find(sum12)!=m_map.end())//如果出现过,则value自增
                {
                    m_map.find(sum12)->second++;
                }
                //如果没有出现过,则插入,value=1
                m_map.insert(pair<int,int> (sum12,1));
            }
        }
        int sum34=0;
        int count=0;//和为0的次数
        //遍历数组3和4,在map里面寻找和的相反数,找到了则加上value,没找到则下一个
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                sum34=nums3[i]+nums4[j];
                if(m_map.find(0-sum34)!=m_map.end())
                {
                    count+=m_map.find(0-sum34)->second;
                }
            }
        }
        return count;
    }
};

其他:

class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        unordered_map<int, int> umap; //key:a+b的数值,value:a+b数值出现的次数
        // 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中
        for (int a : A) {
            for (int b : B) {
                umap[a + b]++;
            }
        }
        int count = 0; // 统计a+b+c+d = 0 出现的次数
        // 再遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
        for (int c : C) {
            for (int d : D) {
                if (umap.find(0 - (c + d)) != umap.end()) {
                    count += umap[0 - (c + d)];
                }
            }
        }
        return count;
    }
};

能通过key直接访问value,不用额外的使用find方法。

383. 赎金信

383. 赎金信 | 代码随想录

笔记:

自己的想法:

magazine里面的字符都统计一下个数存放到一个数据结构里,再遍历ransomnote,去那个数据结构里找,找得到就把个数自减,找不到返回false,并且时刻检测个数是否小于0,如果小于零返回false。

map实现,为什么?key存放magazine串中的字母,value存放个数。(注意:unorder_map.find()找的是keymapkey可以初始化为charlong等其他形式)

一遍过

代码随想录上的思路:

因为题目说只有小写字母,那可以采用空间换取时间的哈希策略,用一个长度为26的数组来记录magazine里字母出现的次数。

然后再用ransomNote去验证这个数组是否包含了ransomNote所需要的所有字母。

依然是数组在哈希法中的应用。

一些同学可能想,用数组干啥,都用map完事了,其实在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!

实操出现问题:

unorder_map.find()找的是keymapkey可以初始化为charlong等其他形式

代码:

我自己的:

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        unordered_map<char,int> magazine_map;//用于存放magazine
        //unordered_map<char,int> ransomNote_map;//ransomNote
        for(int i=0;i<magazine.size();i++)//将magazine转化为map
        {
            magazine_map[magazine[i]]++;
        }
        //相减
        //怎么遍历一个map?不遍历map,而直接遍历string即可
        for(int i=0;i<ransomNote.size();i++)
        {
            char n=ransomNote[i];
            if(magazine_map.find(n)!=magazine_map.end())//如果能找到则对应的value自减
            {
                magazine_map[n]--;
                if(magazine_map[n]<0)//如果小于零,则出现magazine内的字母不够的情况
                {
                    return false;
                }
            }
            else//如果找不到,说明不能由magazine里面的字符构筑,返回false
            {
                return false;
            }
        }
        return true;
    }
};

代码随想录上的:

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26] = {0};
        //add
        if (ransomNote.size() > magazine.size()) {
            return false;
        }
        for (int i = 0; i < magazine.length(); i++) {
            // 通过record数据记录 magazine里各个字符出现次数
            record[magazine[i]-'a'] ++;
        }
        for (int j = 0; j < ransomNote.length(); j++) {
            // 遍历ransomNote,在record里对应的字符个数做--操作
            record[ransomNote[j]-'a']--;
            // 如果小于零说明ransomNote里出现的字符,magazine没有
            if(record[ransomNote[j]-'a'] < 0) {
                return false;
            }
        }
        return true;
    }
};

15.三数之和

梦破碎的地方!| LeetCode:15.三数之和_哔哩哔哩_bilibili

第15题. 三数之和 | 代码随想录

笔记:

用双指针法:首先将数组从小到大排序,一个循环内,左指针指向i+1,右指针指向末尾,如果i+left+right>0,说明大了,这个数要减小只能right--,同理如果小于0,只能left++

去重细节:

i的去重:和前一个(已经遍历过的那个i)对比,如果相同,不再遍历,直接i++(即continue

leftright的去重:left如果和left+1相同,则往下遍历,不管当下的left;如果rightright-1相同,则往下遍历,不管当下的``right

去重的逻辑详细看文章第15题. 三数之和 | 代码随想录

实操出现的问题:

1.二维数组的插入:result.push_back(vector<int> {nums[i],nums[left],nums[right]});//把当前的结果放进result

2.什么时候去重leftright:应该再找到一个符合的结果后进行去重leftright,不然会导致漏掉遍历的。

代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;//结果数组
        int result_hangshu=0;//存放第几个结果
        sort(nums.begin(),nums.end());//从小到大排序
        if(nums[0]>0)
            return {};
        for(int i=0;i<nums.size();i++)//遍历整个数组
        {
            if(i>0&&nums[i]==nums[i-1])//对i去重
                continue;
            int left=i+1;
            int right=nums.size()-1;//指向末尾
            while(right>left)//left和right遍历
            {
                if((nums[right]+nums[left]+nums[i])>0)//结果大了,需要让这个和变小只能是right--
                    right--;
                else if((nums[right]+nums[left]+nums[i])<0)//结果小了,需要让这个和变小只能是left++
                    left++;
                else if((nums[right]+nums[left]+nums[i])==0)//找到目标值
                {
                    result.push_back(vector<int> {nums[i],nums[left],nums[right]});//把当前的结果放进result
                    //去重left和right
                    while(right>left&&nums[left]==nums[left+1])
                        left++;
                    while(right>left&&nums[right]==nums[right-1])
                        right--;
                    left++;
                    right--;
                }
            }
        }
        return result;
    }
};

没有操作减枝!

9.四数之和

笔记:

和上面的题目类似,多加一层循环即可

实操出现的问题:

1.第二次循环没有注意nums[i]+nums[k]是一个整体

2.注意如果是较大的整型相加会溢出,用long来接收运算结果

代码:

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) {
            	break; // 这里使用break,统一通过最后的return返回
            }
            // 对nums[k]去重
            if (k > 0 && nums[k] == nums[k - 1]) {
                continue;
            }
            for (int i = k + 1; i < nums.size(); i++) {
                // 2级剪枝处理
                if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) {
                    break;
                }

                // 对nums[i]去重
                if (i > k + 1 && nums[i] == nums[i - 1]) {
                    continue;
                }
                int left = i + 1;
                int right = nums.size() - 1;
                while (right > left) {
                    // nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
                    if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target) {
                        right--;
                    // nums[k] + nums[i] + nums[left] + nums[right] < target 会溢出
                    } 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]});
                        // 对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;
    }
};

1

posted @ 2026-01-20 20:28  欧尼酱ovo  阅读(0)  评论(0)    收藏  举报