leetcode200题之哈希表(一)

1. 四数相加Ⅱ (leetcode 454题)

用map存储前两个数组的和,然后计算c和d的和,最后在map中找是否存在c和d的和的相反数

class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        unordered_map<int, int> m;
        int res=0;
        for(auto a:A){
            for(auto b:B){
                m[a+b]++;
            }
        }
        for(auto c:C){
            for(auto d:D){
                if(m.find(-c-d)!=m.end())  res += m[-c-d];
            }
        }
        return res;
    }
};

2. 分糖果(leetcode 575题)

找到唯一元素数量的另一种方法是遍历给定 candies 数组的所有元素,并继续将元素放入集合中。通过集合的属性,它将只包含唯一的元素。最后,我们可以计算集合中元素的数量,例如 count。要返回的值将再次由 min(count,n/2) 给出,如前面的方法所述。其中 n 表示 candies 数组的大小。

TIPS:也可以先排序,并通过比较排序数组的相邻元素来找出唯一的元素。对于找到的每个新元素(与前一个元素不同),我们需要更新 count。  O(nlogn)

class Solution {
public:
    int distributeCandies(vector<int>& candies) {
        unordered_set<int> s;
        for(auto c:candies){
            s.insert(c);
        }
        return s.size()<candies.size()/2 ? s.size() :  candies.size()/2;
    }
};

3.  宝石与石头(leetcode 771题)

class Solution {
public:
    int numJewelsInStones(string J, string S) {
        unordered_map<char, int> m;
        for(auto s:S){
            m[s]++;
        }
        int res=0;
        for(auto j:J){
            res += m[j]; 
        }
        return res;
    }
};

4. 最长回文串(leetcode 409题)

对于每个字符 ch,假设它出现了 num 次,我们可以使用该字符 num / 2 * 2 次,在回文串的左侧和右侧分别放置 num / 2 个字符 ch,其中 / 为整数除法。

如果有任何一个字符 ch 的出现次数 num 为奇数(即 num% 2 == 1),那么可以将这个字符作为回文中心,注意只能最多有一个字符作为回文中心。在代码中,我们用 len 存储回文串的长度,由于在遍历字符时,len 每次会增加 num / 2 * 2,因此 len 一直为偶数。但在发现了第一个出现次数为奇数的字符后,我们将 len 增加 1,这样 len 变为奇数,在后面发现其它出现奇数次的字符时,我们就不改变 len 的值了。

class Solution {
public:
    int longestPalindrome(string s) {
        unordered_map<char, int> m;
        for(auto str: s){
            ++m[str];
        }
        int len=0;
        for(auto c:m){
            int num=c.second;
            len += num/2*2;
            if(num%2==1 && len%2==0){
                len++;
            }
        }
        return len;
    }
};

5. 和为K的子数组(leetcode 560题)

计算前缀和

// 计算前缀和数组
vector<int> preSum(len+1)
preSum[0] = 0;
for (int i = 0; i < len; i++) {
    preSum[i + 1] = preSum[i] + nums[i];
}

假如存在区间[left,right],使得在[left,right]这个区间的子数组的和为k。换句话说,就是前right项和减去前left-1项和等于k,即前left-1项和等于前right项和减去k。

可以这样做,在扫描数组的同时,假设当前扫到第i位,记录它的前i项和sum,用该和减去k,即sum-k,判断sum-k是否为某个位置的前n项和,若是,更新统计量。 

TIPS:本题和上文四数相加类似。

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int sum=0,res=0;
        unordered_map<int, int> mp;
        mp[0]=1;
        for(auto num:nums){
            sum += num;
            if(mp.find(sum-k)!=mp.end())  res += mp[sum-k];
            mp[sum]++;
        }
        return res;
    }
};

/*mp[0]=1解释:
    计算完包括了当前数前缀和以后,我们去查一查在当前数之前,有多少个前缀和等于 sum-k 呢?
这是因为满足 sum - (sum - k) == k 的区间的个数是我们所关心的。

    对于一开始的情况,下标 0 之前没有元素,可以认为前缀和为 0,个数为 1 个,因此mp[0]=1
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值