三 哈希表
-
快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
-
数组,set ,map 都可以作为其数据结构
242. 有效的字母异位词
-
给定两个字符串
*s*
和*t*
,编写一个函数来判断*t*
是否是*s*
的字母异位词。注意:若
*s*
和*t*
中每个字符出现的次数都相同,则称*s*
和*t*
互为字母异位词。 -
示例 1:
输入: s = "anagram", t = "nagaram" 输出: true
示例 2:
输入: s = "rat", t = "car" 输出: false
-
bool isAnagram(string s, string t) { int record[26] = {0}; for(auto i:s) { record[i-'a']++; } for(auto i:t) { record[i-'a']--; } for(auto i:record) { if(i != 0) { return false; } } return true; }
-
直接开数组做哈希表,统计出现的次数
349. 两个数组的交集
-
给定两个数组
nums1
和nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 -
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2] 示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出:[9,4] 解释:[4,9] 也是可通过的
-
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { vector<int>record(1001,-1); //用-1表示没出现过,跟0区分开 vector<int>result; for(auto &i: nums1) { record[i] = 1; } for(auto& i: nums2) { if(record[i] == 1) { record[i] = 0; } } for(int i =0;i < 1001;i++ ) //要处理的东西是recode 的下标 { if( record[i] == 0 ) result.push_back(i); } return result; }
-
题目限制了数据的个数以及大小,所以建一个数组做哈希表
-
set的使用
-
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { unordered_set<int>result_set; unordered_set<int>nums_s(nums1.begin(),nums1.end()); for(int i : nums2) { if(nums_s.find(i) != nums_s.end()) { //result_set.insert(i); result_set.emplace(i); } } return vector<int>(result_set.begin(),result_set.end()); }
202. 快乐数
-
编写一个算法来判断一个数
n
是不是快乐数。「快乐数」 定义为:
-
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
-
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
-
如果这个过程 结果为 1,那么这个数就是快乐数。
如果
n
是 快乐数 就返回true
;不是,则返回false
。 -
-
示例 1:
输入:n = 19 输出:true 解释: 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1
示例 2:
输入:n = 2 输出:false
-
bool isHappy(int n) { unordered_set<int>record; while(record.find(n) == record.end()) // 没有找到 { record.emplace(n); int sum = 0; while( n != 0 ) { sum += ( (n%10)* (n%10)); n = n/10; } if(sum == 1) return true; n =sum; } return false; }
-
和如果出现过就循环
1. 两数之和
-
给定一个整数数组
nums
和一个整数目标值target
,请你在该数组中找出 和为目标值target
的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
-
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6 输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6 输出:[0,1]
-
vector<int> twoSum(vector<int>& nums, int target) { // 暴力 // int sum = 0; // for(int i = 0;i< nums.size()-1;i++) // { // for(int j = i+1;j< nums.size();j++) // { // if(nums[i] + nums[j] == target) // return vector<int>{i,j}; // } // } // return vector<int>{}; //哈希 unordered_map<int,int>umap; for(int i =0;i< nums.size();i++) { umap.emplace(nums[i],i); } for(int i = 0;i< nums.size();i++) { if( umap.find( target - nums[i] ) != umap.end() && i != umap[target-nums[i]] ) // 有可能是nums[i] 是target的一半 { //printf("%d %d %d \n",i,umap[target-nums[i]],target-nums[i]); return vector<int>{i, umap[target-nums[i]] }; } } //printf("31\n"); return vector<int>{}; }
-
先将所有的值加入哈希,有可能找到自身,所以需要额外处理
-
vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int,int>umap; for(int i = 0;i< nums.size();i++) { auto iter = umap.find(target - nums[i]); if( iter != umap.end() ) { return {i, iter->second };//vector<int>{i, iter->second }; } umap.emplace(nums[i],i); } return {}; }
-
边遍历边加入, 就避免了找到自身
454. 四数相加 II
-
给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:
0 <= i, j, k, l < n nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
-
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) { unordered_map<int,int>summap; int result = 0; for(auto i :nums1) { for(auto j:nums2) { summap[i+j]++; //记录前俩数组和以及出现次数 } } for(auto i :nums3) { for(auto j:nums4) { auto iter = summap.find(-(i+j)); if( iter != summap.end() ) { result += summap[-(i+j)]; } } } return result; }
-
先记录前俩数组和以及出现次数
15. 三数之和
-
给你一个整数数组
nums
,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足i != j
、i != k
且j != k
,同时还满足nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为
0
且不重复的三元组。注意:答案中不可以包含重复的三元组。
-
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
-
vector<vector<int>> threeSum(vector<int>& nums) { sort(nums.begin(),nums.end()); vector<vector<int>>result; multimap<int,int>mmap; for(int i = nums.size()-1;i>=0;i--) { mmap.emplace(nums[i],i); } for(int i =0;i< nums.size();i++) { if(nums[i] > 0) //第一个数 break; if(i>0 && nums[i] == nums[i-1]) // 三元组a去重 continue; for(int j = i+1;j<nums.size();j++) { if(j> i+1 && nums[j] == nums[j-1]) //三元组b去重 continue; int c = -(nums[i] + nums[j]); auto iter = mmap.find(c); if( iter != mmap.end() && iter->second > j)//要保证找的c在a b之后 { result.push_back({nums[i],nums[j],c}); } } } return result; }
-
去重很麻烦,a b的去重可以统一起来
-
对于c一定保证是位于a b 之后的 所以可以从后往前找
-
vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> result; sort(nums.begin(),nums.end()); //三个数 nums[i] + nums[left] + nums[right] for(int i = 0;i<nums.size();i++) { // 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了 if(nums[i] > 0 ) return result; if(i > 0 && nums[i] == nums[i-1]) continue; int left = i+1; int right = nums.size()-1; while(left < right) { //去重逻辑 if(right <nums.size()-1 && nums[right] == nums[right+1]) { right--; continue; } if(left > i+1 && nums[left] == nums[left-1]) { left++; continue; } 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]}); // 找到答案时,双指针同时收缩 right--; left++; //while(right> left && nums[right] ==) } } } return result; }
-
双指针的移动 : 先固定第一个数, 剩下的两个数采用双指针
-
去重逻辑保持一致 : 去重是先使用之后再去重
-
双指针适用于 排好序的数组,如果没有排好序且要求下标则不适合双指针
-
定一找二
-
本题的哈希表只能是三重for ,然后用哈希表去找剩下的一个
18. 四数之和
-
给你一个由
n
个整数组成的数组nums
,和一个目标值target
。请你找出并返回满足下述全部条件且不重复的四元组[nums[a], nums[b], nums[c], nums[d]]
(若两个四元组元素一一对应,则认为两个四元组重复):-
0 <= a, b, c, d < n
-
a
、b
、c
和d
互不相同 -
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:
输入:nums = [2,2,2,2,2], target = 8 输出:[[2,2,2,2]]
-
-
vector<vector<int>> fourSum(vector<int>& nums, int target) { if(nums.size() < 4) return {}; vector<vector<int>>result; sort(nums.begin(),nums.end()); for(int i = 0;i< nums.size();i++) { if(nums[i]> target && nums[i] > 0) break; // 剪枝处理 if(i> 0 && nums[i] == nums[i-1]) continue; //去重 for(int j = i+1;j< nums.size();j++) { if(nums[i] + nums[j] > target && nums[i] + nums[j] >0) break; // 剪枝处理 if(j> i+1 && nums[j] == nums[j-1]) continue; //去重 long sum = (long)target - nums[i] - nums[j]; int left = j+1,right = nums.size()-1; while(left < right) { if(right< nums.size()-1 && nums[right] == nums[right+1]) //去重 { right--;continue; } if(left > j+1 && nums[left] == nums[left-1]) //去重 { left++;continue; } if( nums[left] + nums[right] > sum) right--; else if(nums[left] + nums[right] < sum) left++; else{ result.push_back({nums[i],nums[j],nums[left],nums[right]}); left++; right--; } } } } return result; }