今天的四道题是哈希表
题目要求s能构成t,并且所有的字母都要使用一次,这就意味着不仅s与t的长度要一致,s与t的字母种类也一致,且每种字母的个数也相同。
AC代码:
class Solution {
public:
bool isAnagram(string s, string t) {
if (s.size() != t.size())
return false;
unordered_map<char, int> sCount;
for (char c : s) {
sCount[c]++;
}
for (char c : t) {
if (sCount.find(c) == sCount.end() || sCount[c] <= 0) {
return false;
}
sCount[c]--;
}
return true;
}
};
//只针对小写字母,可以使用26大小的数组
class Solution {
public:
bool isAnagram(string s, string t) {
int record[26] = {0};
for (int i = 0; i < s.size(); i++) {
// 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
record[s[i] - 'a']++;
}
for (int i = 0; i < t.size(); i++) {
record[t[i] - 'a']--;
}
for (int i = 0; i < 26; i++) {
if (record[i] != 0) {
// record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
return false;
}
}
// record数组所有元素都为零0,说明字符串s和t是字母异位词
return true;
}
};
- 可以使用
nums1_set.find(num) == nums1_set.end()来判断是否已经存在num - 也可以直接使用
<iterator,bool> insert( const value_type& value );(来源unordered_set::insert)或者<iterator, bool> emplace( Args&&... args );(来源unordered_set::emplace),这两个函数会自动放弃重复的插入操作,并返回false
AC代码:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> nums1_set;
for(int num:nums1){
if(nums1_set.find(num) == nums1_set.end()){
nums1_set.emplace(num);
}
}
vector<int> ans;
for(int num:nums2){
if(nums1_set.find(num) != nums1_set.end()){
ans.push_back(num);
nums1_set.erase(num);
}
}
return ans;
}
};
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重
unordered_set<int> nums_set(nums1.begin(), nums1.end());
for (int num : nums2) {
// 发现nums2的元素 在nums_set里又出现过
if (nums_set.find(num) != nums_set.end()) {
result_set.insert(num);
}
}
return vector<int>(result_set.begin(), result_set.end());
}
};
这道题难点在于非快乐数时该如何判断,重点在于非快乐数会无限循环,也就意味着n所变化的数有着重复,因此使用一个哈希表记录n变化的数,若有重复,则不是快乐数。
AC代码:
class Solution {
public:
bool isHappy(int n) {
unordered_set<int> n_set;
while (n_set.find(n) == n_set.end()) {
n_set.emplace(n);
n = GetHappyNum(n);
if (n == 1)
return true;
}
return false;
}
private:
int GetHappyNum(int n) {
int happyNum = 0;
int num = 0;
while (n > 0) {
num = n % 10;
happyNum += num * num;
n /= 10;
}
return happyNum;
}
};
class Solution {
public:
// 取数值各个位上的单数之和
int getSum(int n) {
int sum = 0;
while (n) {
sum += (n % 10) * (n % 10);
n /= 10;
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> set;
while(1) {
int sum = getSum(n);
if (sum == 1) {
return true;
}
// 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
if (set.find(sum) != set.end()) {
return false;
} else {
set.insert(sum);
}
n = sum;
}
}
};
用unordered_multimap记录每个数的值与对应的下标,然后检查每个数nums[i]是否存在对应的target - nums[i],要注意的一点就是当nums[i] = target/2时,需要判断是否还存在额外的nums[i],如果只有一个满足nums[i] = target/2的nums[i],那么是不满足条件的。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_multimap<int, int> numToIndex;
for (int i = 0; i < nums.size(); ++i) {
numToIndex.emplace(nums[i], i);
}
vector<int> ans(2);
for (int i = 0; i < nums.size(); ++i) {
auto it = numToIndex.find(target - nums[i]);
if (it != numToIndex.end()) {
// nums[i] = target/2
if (it->second == i) {
if (numToIndex.count(nums[i]) > 1) {
auto ranges = numToIndex.equal_range(nums[i]);
ans[0] = i;
ans[1] = (++ranges.first)->second;
break;
}
} else {
ans[0] = i;
ans[1] = it->second;
break;
}
}
}
return ans;
}
};
//边遍历边寻找
//对于重复的情况,因为题目保证每种输入只会对应一个答案
//所以此时,这种特殊情况也可以也转化为普通的情况
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
std::unordered_map <int,int> map;
for(int i = 0; i < nums.size(); i++) {
// 遍历当前元素,并在map中寻找是否有匹配的key
auto iter = map.find(target - nums[i]);
if(iter != map.end()) {
return {iter->second, i};
}
// 如果没找到匹配对,就把访问过的元素和下标加入到map中
map.insert(pair<int, int>(nums[i], i));
}
return {};
}
};