代码随想录算法训练营|哈希表内容复习

哈希表内容复习

有效的字母异位词

242. 有效的字母异位词 这个题的思路还是比较简单的,就是中间hash数组进行存储的时候不要写错了

点击查看代码
class Solution {
public:
    bool isAnagram(string s, string t) {
        int hash[26];
        for (int i = 0; i < s.size(); i++) (hash[s[i] - 'a'])++;
        for (int j = 0; j < t.size(); j++) (hash[t[j] - 'a'])--;
        for (int i = 0; i < 26; i++) {
            if (hash[i] != 0) return false;
        }
        return true;
    }
};

两个数组的交集

349. 两个数组的交集 这个题有两种思路,一种使用数组做哈希表,用数组就是常见的hash[nums[i]]++这样的处理方式。还有一种思路是用set做哈希表,就是用unordered_map<int> numsinsert操作,来进行添加。特别注意这里的是insert操作,而不是数组,字符串可以用push_back,队列和栈用push

使用数组

点击查看代码
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        int hash[1001];
        unordered_set<int> result;
        for (int i = 0; i < nums1.size(); i++) hash[nums1[i]]++;
        for (int i = 0; i < nums2.size(); i++) {
            if (hash[nums2[i]] != 0) {
                result.insert(nums2[i]);
            }
        }
        return vector<int> (result.begin(), result.end());
    }
};

使用set

点击查看代码
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result;
        unordered_set<int> nums;
        for (int i = 0; i < nums1.size(); i++) {
            nums.insert(nums1[i]);
        }
        for (int i = 0; i < nums2.size(); i++) {
            if (nums.find(nums2[i]) != nums.end()) {
                result.insert(nums2[i]);
            }
        }
        return vector<int> (result.begin(), result.end());
    }
};

快乐数

202. 快乐数 这个题的思路不难,关键是要想到用哈希表来进行存储,这里注意要存储的值是最后每一次计算得到的sum,刚开始犯了一个小错误,把每次查询的部分加在了分解计算的部分中。导致在用例19的最后一次计算\(1^2+0^2+0^2\)的时候会出现两次重复的1导致查询重复。

点击查看代码
class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> query;
        while (n != 1) {
            int sum = 0;
            // 分解计算
            while (n) {
                int m = n % 10;
                n = n / 10;
                sum += m * m;
            }
            // 查询
            if (query.find(sum) == query.end()) {
                    query.insert(sum);
            } else {
                // cout << sum << endl;
                return false;
            }
            // 赋值
            n = sum;
        }
        return true;
    }
};

两数之和

1. 两数之和 两数之和还是比较简单的,就是用map结构来存储每个nums[i]和对应的索引值

点击查看代码
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> map;
        for (int i = 0; i < nums.size(); i++) {
            if (map.find(target - nums[i]) != map.end()) {
                return {i, map.find(target - nums[i])->second};
            }
            else map.insert(pair<int, int> (nums[i], i));
        }
        return {};
    }
};

四数相加Ⅱ

454. 四数相加 II 关于map的作用,在这里就是记录nums1和nums2中加和的个数,比如加起来是3 的有四个,加起来是4的有5个这样。这个题的核心就是用map来进行哈希表查找,最终将对应的值加起来即可

点击查看代码
class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int, int> map;
        for (int i = 0; i < nums1.size(); i++) {
            for (int j = 0; j < nums2.size(); j++) {
                int value = nums1[i] + nums2[j];
                map[value]++;
            }
        }
        int count = 0;
        for (int i = 0; i < nums3.size(); i++) {
            for (int j = 0; j < nums4.size(); j++) {
                int result = 0 - (nums3[i] + nums4[j]);
                if (map.find(result) != map.end()) count += map.find(result)->second;
            }
        }
        return count;
    }
};

赎金信

383. 赎金信 这个题直接仿照242. 有效的字母异位词做就可以,思路也是用的那个。果然就是这样做

点击查看代码
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int hash[26];
        for (int i = 0; i < magazine.size(); i++) {
            hash[magazine[i] - 'a']++;
        }
        for (int i = 0; i < ransomNote.size(); i++) {
            hash[ransomNote[i] - 'a']--;
        }
        for (int i = 0; i < 26; i++) {
            if (hash[i] < 0) return false;
        }
        return true;
    }
};

三数之和

15. 三数之和 这个题在开始的时候遇到对a的去重有点懵住了,为什么要对a去重呢?不是组内元素可以重复吗?

其实这么看,后面的两个left和right是和a的结果加起来为0的,如果a一直都是一个值。[a,(0-a)]后面两部分和就都是0-a,所以这样的三元组就会出现重复。

那该如何对a去重,到底是if (nums[i] == nums[i + 1])还是if (nums[i] == nums[i - 1])

其实这里但看a的话,是看不出来全貌的,要结合left看,也就是a的下一位。拿[-1,-1,2]举例。如果是if (nums[i] == nums[i + 1]),开始的时候,a=-1,这种情况continue了,下面,a=-1,第二种情况a不会跳过,此时left=2。但是我们发现了,漏掉了一种情况,就是a=-1的时候,left可以等于-1的。注意:三元组内的[a,left,right]是可以有重复的,但是三元组和三元组之间是不能有重复的

这次中间的循环写成这样的判断了,但是就是对于[-1,0,0,0,0]这种情况就无法进行去重了,result会添加好多重复的vector


for (; left < right; ) {
	if (nums[i] + nums[left] + nums[right] == 0) result.push_back(vector<int> {nums[i], nums[left], nums[right]});
	else {
		while (nums[i] + nums[left] + nums[right] < 0) left++;
		while (nums[i] + nums[left] + nums[right] > 0) right--;
	}
	left++;
	right--;
}

正确的是

for (; left < right; ) {
	if (nums[i] + nums[left] + nums[right] > 0) right--;
	else if (nums[i] + nums[left] + nums[right] < 0) left++;
	else {
		result.push_back({nums[i], nums[left], nums[right]});
		while (left < right && nums[left] == nums[left + 1]) left++;
		while (left < right && nums[right] == nums[right - 1]) right--;
		left++;
		right--;
	}
}
点击查看代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> result;
        if (nums[0] > 0) return result;
        for (int i = 0; i < nums.size(); i++) {
            int a = i;
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            int left = i + 1;
            int right = nums.size() - 1;
            for (; left < right; ) {
                if (nums[i] + nums[left] + nums[right] > 0) right--;
                else if (nums[i] + nums[left] + nums[right] < 0) left++;
                else {
                    result.push_back({nums[i], nums[left], nums[right]});
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    while (left < right && nums[right] == nums[right - 1]) right--;
                    left++;
                    right--;
                }
            }
        }
        return result;
    }
};

四数之和

18. 四数之和 四数之和,在回顾了昨天的三树之和之后就变得简单不少,也好理解了。就是需要注意一点,在二级去重的时候,那么判断条件不要写错,if (i > k + 1 && ...)

点击查看代码
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> result;
        for (int k = 0; k < nums.size(); k++) {
            // 一级剪枝
            if (nums[k] > target && nums[k] > 0 && target > 0) continue;
            // 一级去重
            if (k > 0 && nums[k] == nums[k - 1]) continue;
            for (int i = k + 1; i < nums.size(); i++) {
                // 二级剪枝
                if (nums[k] + nums[i] > target && nums[k] + nums[i] > 0 && target > 0) continue;
                // 二级去重
                if (i > k + 1 && nums[i] == nums[i - 1]) continue;
                int left = i + 1;
                int right = nums.size() - 1;
                for (; left < right; ) {
                    if ((long) nums[k] + nums[i] + nums[left] + nums[right] < target) left++;
                    else if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target) right--;
                    else {
                        result.push_back(vector<int> {nums[k], nums[i], nums[left], nums[right]});
                        while (left < right && nums[left] == nums[left + 1]) left++;
                        while (left < right && nums[right] == nums[right - 1]) right--;
                        left++;
                        right--;
                    }
                }
            }
        }
        return result;
    }
};

做个小总结

哈希表的内容感觉写的很舒服,大致可以分成两部分内容

哈希法

从哈希表中的数组的用法242. 有效的字母异位词和赎金信,二者的思路和方法基本一致。还有set的用法349. 两个数组的交集和202. 快乐数。再到之后就是map的用法了。两数之和,四数相加都是map的典型例题

双指针法

这里的一些题目可以用双指针法来做。包括梦破碎的三数之和还有四数之和,都是用双指针来解更快更简便。

posted on 2025-05-06 08:56  bnbncch  阅读(9)  评论(0)    收藏  举报