D10 454. 四数相加Ⅱ 383. 赎金信

454 四数相加Ⅱ(力扣:[https://leetcode.cn/problems/4sum-ii/])

条件:给定四个长度均为n的数组,要满足nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0,而元组{ i, j, k, l }不重复,返回所有符合条件的元组数量;
Tips:

  1. 为了降低时间复杂度,将原问题的分别查找四个元组改成两两一组,分为两两是因为另一种分法为一三,时间复杂度依然高;分组不限顺序(AB+CD或者AC+BD...)这里为了方便分为AB+CD,这样就将原求解式变成了A+B = 0 - (C+D)→ new1 = 0 - new2,其中new1 = A+B、new2 = C+D,new1、new2为新set的key;由于new1为和、也就是一个key可能会对应多个AB的值,所以每个new1的value统计有多少可以算出当前key的AB组合;
  2. 注意n为索引/下标,nums1[n] + nums2[n] 才是参与凑0计算的值;而在迭代器遍历中,for( int n1 : nums1 )中的n1为元素nums1[i]而非下标i值!
  3. (以n1为元素而非下标为前提)访问key/value的方法在代码里展示了两种,一种是key = n1+n2, value = abSum[ n1+n2 ];另一种是使用find函数,但如果找不到target从而返回abSum.end()会导致未定义行为报错, 因此多定义一个auto it = abSum.find( n1+n2 ),在it != abSum.end()时再使用it->second为value,->first或n1+n2为key;

代码来自AI:

点击查看代码
class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        //先统计n1+n2所有可能的sum的情况,key为sum、value为sum出现的次数
        unordered_map<int,int>abSum;
        int n = nums1.size();

        //数组长度相同,遍历时用一个数组取size即可
        for( int n1 = 0; n1 < n; n1++ ){
            //每个num1的元素算一遍和所有nums2元素的sum
            for( int n2 = 0; n2 < n; n2++ ){
                //当前sum为新sum时,存入新key同时设置value为1
                if( abSum.find( nums1[n1] + nums2[n2] ) != abSum.end() ){
                    abSum[ nums1[n1] + nums2[n2] ]++;
                }else{
                    //当该sum存在时,更新该sum的value+1
                    abSum.insert({nums1[n1] + nums2[n2], 1});
                }
            }
        }
        
        int ans = 0;
        //统计结束后挨个计算target = 0 - nums3[?] -nums4[?]
        for( int n3 : nums3 ){
            for( int n4 : nums4 ){
                //这种写法n3对应的是nums3[?]而非下标?,因此计算target时直接用n3和n4
                int target = 0 - n3 - n4;

                //如果能在abSum里找到对应的target
                if( abSum.find(target) != abSum.end() ){
                    //将结果计数值叠加当前target的value
                     ans += abSum[target]; 
                }
                //或者使用迭代器:
                //auto it = abSum.find(target)
                //if( it != abSum.end() ){ ans += it->second; }
            }
        }

        return ans;
    }
};

383 赎金信(力扣:[https://leetcode.cn/problems/ransom-note/])
条件:给定两个只有小写字母的字符串AB,要求在字符串B中找到足够数量的组成A的字母,B中每个字母只能使用一次,成功返回true;
Tips:

  1. 原本的思路是使用一个map,key储存A里的字母减去'a'的值,value存储该值出现次数,再遍历B查询B的每个元素是否在A中出现,每出现一次将A的value减一,最后再查询A中是否还有value非0的元素;这种方法比较复杂,原因为map还要额外做红黑树和哈希函数、数据量大的时候会比较耗时,可以直接使用数组或者字符串操作;参考链接
  2. 下面使用数组的方法先遍历了A进行record++,再遍历B进行record--,最后遍历A确认没有record>0, 而上面的参考先遍历B进行record++,而后遍历A进行record--,只要出现<0则返回false,这种写法比前一种少了一遍遍历;

使用数组:

点击查看代码
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        //使用数组会有“下标”和“元素值”两个部分可以定义,这里依旧采用字母异位词的思路,使用字母减去'a'作为下标,元素值存储该字母出现次数;
        int record[26] = {};

        //题目需要考虑字母数量,所以如果magazine字符总数少于ransome则直接返回false
        if( magazine.length() < ransomNote.length() ){
            return false;
        }

        //遍历ransomNote进行存储
        for( int tmp = 0; tmp < ransomNote.length(); tmp++ ){
            record[ ransomNote[tmp] - 'a' ]++;
        }

        //遍历magazine
        for( int tmp = 0; tmp < magazine.length(); tmp++ ){
            record[ magazine[tmp] - 'a' ]--;
        }

        //再次遍历ransomNote,如果存在值>0则返回false
        for( int tmp = 0; tmp < 26; tmp++ ){
            if( record[tmp] > 0 ){
                return false;
            }
        }

        return true;

    }
};

另一种使用字符串操作, 注意要内层遍历需要被执行删除的A字符串,这样能保证B字符串一直被按照顺序遍历、没有跳过元素:

点击查看代码
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        for (int i = 0; i < magazine.length(); i++) {
            for (int j = 0; j < ransomNote.length(); j++) {
                // 在ransomNote中找到和magazine相同的字符
                if (magazine[i] == ransomNote[j]) {
                    ransomNote.erase(ransomNote.begin() + j); // ransomNote删除这个字符
                    break;
                }
            }
        }
        // 如果ransomNote为空,则说明magazine的字符可以组成ransomNote
        if (ransomNote.length() == 0) {
            return true;
        }
        return false;
    }
};
posted @ 2026-04-11 19:38  SCONLY  阅读(5)  评论(0)    收藏  举报