242-有效的字母异位词
题目链接:有效的字母异位词
1.排序
算法描述:对字符串s和t进行排序后就可以直接比较排序后的字符串是否相等。
class Solution {
public:
bool isAnagram(string s, string t) {
//排序解法
bool result = false;
if(s.length() != t.length()){
return result;
}
sort(s.begin() , s.end());
sort(t.begin() , t.end());
if(s == t)
result = true;
return result;
}
};
时间复杂度:C++中提供的sort排序使用的是快速排序,时间复杂度为O(nlogn)
2.数组结构的哈希表
算法描述:先遍历字符串s,使用哈希表记录每个字母出现的次数。再遍历字符串t,在哈希表中减去每个字母出现的次数。若哈希表每个元素都为0,则符合题意。
class Solution {
public:
bool isAnagram(string s, string t) {
// 哈希解法
int hash[26] = {0};
if(s.length() != t.length()){
return false;
}
for(int i = 0; i < s.length(); i++){
hash[s[i] - 'a']++;
}
for(int i = 0; i < t.length(); i++){
hash[t[i] - 'a']--;
}
for(int i = 0; i< 26; i++){
if(hash[i] != 0)
return false;
}
return true;
}
};
时间复杂度:遍历字符串,因此时间复杂度为O(n)
空间复杂度:因为定义的是一个常量大小的辅助数组,所以空间复杂度为O(1)
349-两个数组的交集
题目链接:两个数组的交集
思路:其实一上来的想法就是像上一道题一样使用数组结构的哈希表,但由于题目中nums中的数据范围较大,因此设置hash[1000]的数组可能会造成极大的空间浪费,因此放弃使用数组结构的哈希表。
1.set结构的哈希表
算法描述:将nums1转换成哈希表的形式存储,遍历nums2查找在哈希表中是否存在,存在则加入result。
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
//set结构的哈希表
unordered_set<int> result; // unordered_set中的数据不允许重复 直接利用数据结构去重
unordered_set<int> nums_set(nums1.begin(), nums1.end());
for(int num :nums2){
if(nums_set.find(num) != nums_set.end())
result.insert(num);
}
return vector<int>(result.begin(), result.end()); //强制类型转换
}
};
解题关键在于选择合适的数据结构:哈希表理论基础
2.暴力解法
算法描述:两层for循环遍历数组,若nums2中存在nums1中有的元素,则加入到result中。遍历完之后再通过排序去重。
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
// 暴力解法
vector<int> result;
for(int i = 0; i< nums1.size(); i++){
int number = nums1[i];
for(int j = 0; j < nums2.size(); j++){
if(nums2[j] == number){
result.push_back(number);
break;
}
}
}
// 排序后去重
sort(result.begin(), result.end());
result.erase(unique(result.begin(), result.end()), result.end());
return result;
}
};
3.排序+双指针(leetcode官方题解)
算法描述:先将nums1和nums2排序,使用双指针分别指向两个数组的起始位置。若指针指向的元素相等,则判断元素是否重复,不重复则加入result中,否则跳过。此时两个指针均向后移动。若nums1指针指向的元素小于nums2指针指向的元素,则nums1指针向后移。反之则nums2指针后移。
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
// 排序+双指针
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
int len1 = nums1.size();
int len2 = nums2.size();
int p1 = 0, p2 = 0;
vector<int> result;
while(p1 < len1 && p2< len2){
int num1 = nums1[p1], num2 = nums2[p2];
if(num1 == num2){
if (!result.size() || num1 != result.back()) {
result.push_back(num1);
}
p1++;
p2++;
}else if (num1 < num2)
{
p1++;
} else {
p2++;
}
}
return result;
}
};
202-快乐数
题目链接:快乐数
思路: 题目中提到可能是无限循环 --> 要注意判断平方和是否出现过,若出现过则存在循环,即不是快乐数直接返回false。快速判断一个数是否存在 --> 哈希表
class Solution {
public:
// 计算位数字的平方和
int bitSquareSum(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 = bitSquareSum(n);
if(sum == 1)
return true;
if(set.find(sum) != set.end())
return false;
set.insert(sum);
n = sum;
}
}
};
1-两数之和
题目链接:两数之和
数据结构的选择:unordered_map
- 在本题中既需要保存元素值,又需要保存下标 --> 选择map
- 不要求键值有序 --> unordered_map
算法描述:遍历数组,存储当前值和坐标,并计算target - nums[i]是否存在,若存在则返回当前下标和查找到的元素的下标。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
// 哈希表
unordered_map<int,int> hash;
for(int i = 0; i < nums.size(); i++){
auto it = hash.find(target - nums[i]);
if(it != hash.end()){
return {it->second,i};
}
hash[nums[i]] = i;
}
return {};
}
};
感觉哈希表的题在算法逻辑上都并没有很难理解,关键在于意识到应该选择哈希来处理并且要选择合适的数据结构。