有效的字母异位词
哈希表的应用:其实本题就是比较两个字符串中每个字母出现的次数是否相等,我们使用一个hash[26]代表a字母到z字母的出现次数,由于a到z的ASCII码是连续的,因此用该字符-'a'的值对应了0-25,分别是数组hash[26]的对应下标。
int hash[26] = { 0 };
for (int i=0;i<s.size(); i++)
{
hash[s[i] - 'a']++;
}
然后为了比较字符串s和t,我们先将s的每个字符存入hash[26]中,然后再遍历t的每一个字符,每遍历到一次,就将该字符的频率-1,最后再遍历hash[26],如果全部值都为0,则完全遍历,输出ture,如果遍历过程有一个不为0,说明不是字母异位词,因此输出false。完整代码:
class Solution {
public:
bool isAnagram(string s, string t) {
int hash[26] = { 0 };
for (int i=0;i<s.size(); i++)
{
hash[s[i] - 'a']++;
}
for (int i = 0; i < t.size(); i++)
{
hash[t[i] - 'a']--;
}
for (int i = 0; i < 26; i++)
{
if (hash[i]) return false;
}
return true;
}
};
两个数组的交集
根据题目的输出我们可以看出最终的交集结果是相同的数字只存储一次,因此我们使用unordered_set存储,因为该set查询的时间复杂度为O(1)。算法思路大致是先用unordered_set存储数组nums1,每一个数字只存储一次,然后再查询nums2中的每一个数字,使用nums.find(nums2[i]) != nums.end()进行判断,find函数会查找[begin,end)区间,当find查找失败时,返回end()。然后我们将查找结果插入到result中,当查找成功插入该元素。由于最终返回类型是vector<int>,我们将unordered_set转换为vector返回。
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> nums (nums1.begin(), nums1.end());//将nums1转换为unordered_set
unordered_set<int> result;
for (int i = 0; i < nums2.size(); i++)
{
if (nums.find(nums2[i]) != nums.end()) result.insert(nums2[i]);
}
vector<int> result_v(result.begin(), result.end());
return result_v;
}
};
快乐数
快乐数是指每一位的平方和等于1。
此题的解题关键是如何表示无限循环。当循环过程中有两次的平方和值相等时,会一直在这两个平方和中间循环。因此判断条件就是当前平方和是否已经出现过,那么我们如何判断当前平方和是否出现过呢,就是通过unordered_set实现。判断当前计算出的平方和sum值是否在set中,如果存在,说明无限循环,返回false。如果不存在且值不为1,则将当前平方和sum存入set中。如果值为1,说明每一位的平方和等于1,那么当前数是快乐数。
int newSum(int n)
{
int sum = 0;
while (n)
{
int n1 = n % 10;
sum += n1 * n1;
n /=10;
}
return sum;
}
class Solution {
public:
bool isHappy(int n) {
int sum = newSum(n);
unordered_set<int> nums;
while (nums.find(sum)==nums.end())
{
if (sum == 1) return true;
nums.insert(sum);
sum = newSum(sum);
}
return false;
}
};
两数之和
朴素法:复杂度O(n^2)
给定一个数组和目标值target,判断数组中是否存在两个数的和等于target,如果存在这样的两个数,返回下标。我们可以通过朴素算法即两层for循环实现,第一层指针i进行遍历整个数组,第二层指针j遍历该元素前面的所有元素,当两个元素满足时,返回{i,j}。
可行性:由于第一层遍历整个数组,因此该元素前面的所有元素都会进行配对,因此能够枚举到所有元素对。
哈希表法:复杂度O(n)
该方法能将复杂度从O(n^2)降到O(n)是因为在第二层循环时直接通过unordered_map进行查询,由于unordered_map底层是哈希表,因此查询时间复杂度为O(1)。第一层遍历将nums[i]插入到map中,由于该题存在相同元素,因此用map实现,key是nums[i]的值,value是下标i,pair<int,int>(nums[i],i)因此可以区分相同的key值。在第二层遍历时,直接查询target-nums[i]是否在map中,如果存在,return { i, map.find(target - nums[i])->second } ,first是key,second是value。如果遍历完都没有return,说明不存在,return{}。
完整代码:
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 };
//first是key,second是value,我们将下标保存到value中
else
{
map.insert(pair<int,int>(nums[i],i));
}
}
return {};
}
};
通过两个数组的交集和两数之和我们可以总结出,当我们相同值元素只存储一次时,使用set,也就是集合,因为集合中的定义就是每种元素只存储一次。当相同元素需要区分时(即都存储),我们使用map,也就是键值对存储,key存储元素值,value存储该元素下标。