Day7 哈希表(二)
2023.12.6
深感抱歉,这几天事情太多了,昨天跟导师出差,整理资料到半夜,一直没空打卡学习,今晚难得有空,先将昨天12.5日的任务补上。
1. 454四数相加Ⅱ
这道题其实还是很好理解的,四个数组的匹配问题,麻瓜一点就是四层for,显然不是我们想要的最优解,尽量减少时间复杂度。延续之前做哈希表题的思想,固定一个值,然后找另一个值。但此处是四个值,因此需要做组合,两两组合或者三一分配。显然两两组合时间复杂度小一点,将四个值变为两个值匹配。分别两层for,将四值之和变为两值之和。
另一个技巧,本题找的是和为0的,我们转换成两个值后,也就是互为相反数,因此代码逻辑比之前的要简单一些。直接看另一个数是否在哈希表中即可。
class Solution {
public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {unordered_map<int, int> map;for(int a:nums1){ //二合一for(int b:nums2){map[a+b]++;}}int count=0;for(int c:nums3){ //二合一且查找匹配for(int d:nums4){if(map.find(0-(c+d))!=map.end()){count += map[0-(c+d)];}}}return count;}
};
2. 383赎金信
这道题很简单,做了之前的哈希表问题,再看这道题就很easy了,将对照字符串遍历,值++;然后遍历待处理字符串,值–;最后遍历map,如果有值<0的,那就问题啦!
class Solution {
public:bool canConstruct(string ransomNote, string magazine) {unordered_map<int,int> map;for(char s:magazine){map[s-'a']++;}for(char s:ransomNote){map[s-'a']--;}for(auto i = map.begin();i!=map.end();i++){if(i->second<0){return false;}}return true;}
};
3. 15三数之和
这道题最开始我就想的继续用map,但代码逻辑很乱,一直写不出来,最后看代码随想录,emmm,绷不住了,这种方法果然不是最优解,本题应该使用双指针,即一个for控制遍历,然后定义一个指针指向i+1,另一个指向末尾。不过,前提是数组要先排序!很巧妙,然后三者值相加,判断大于零还是小于零,大于零,那正数就要变小,所以右侧的左移。小于零,负数要变大,因此左侧的要右移。整体逻辑简单。但存在很多细节。
1.如果遍历i的值,nums[i]都是大于0的,那还有必要继续吗?最小值大于零,三者之和肯定不能为0了。因此直接return。
2.题目要求不重复,就要对三个数进行删选,即相邻值相同的略过
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;int left = i +1;int right = nums.size()-1;if(i>0 && nums[i]==nums[i-1])continue;while(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(vector<int>{nums[i], nums[left], nums[right]});while(left<right && nums[right]==nums[right-1])right--;while(left<right && nums[left]==nums[left+1])left++;right--;left++;}}}return result;}
};
4. 18四数之和
本题与三数之和相同,但外面多一层循环,并且,这次target是指定值,因此在剪枝操作就不能>0就return了,具体代码(用的代码随想录原始代码,因为在出差期间,时间不够,就偷个懒。。。)如下:
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;}
};