有效的字母异位词
题目描述
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1: 输入: s = “anagram”, t = “nagaram” 输出: true
示例 2: 输入: s = “rat”, t = “car” 输出: false
说明: 你可以假设字符串只包含小写字母。
解题思路
总体思路
方式一:使用暴力的方式,使用两层for循环,依次判断字符串s中的每个字符在字符串t中是否都存在,该方法的时间复杂度为O(n^2)
方式二:通过引入哈希表的方式进行判断
- 因为题目提到字符串只包含小写字母,因此字符范围在:a-z之间,大小为26,且字符连续
- 创建一个满足字符范围的数组,初始化为0
- 先对字符串s的每个字符进行遍历,将每个字符出现的次数保存到对应的数组下标中,然后再遍历字符串s,依次删除字符串中每个字符保存在数组中的次数
- 遍历数组,判断数组元素值是否均为0,如果是的话说明两个字符串相同,反之不相同
时空复杂度分析
- 时间复杂度: O(n)
- 空间复杂度: O(1)
代码实现
测试地址:https://leetcode.cn/problems/valid-anagram/
class Solution {
public:
bool isAnagram(string s, string t) {
int ans[26] = {0}; //初始化数组
for (int i = 0; i < s.size(); i++) {
ans[s[i] - 'a']++; //将每个字符出现的次数保存至数组中
}
for (int i = 0; i < t.size(); i++) {
ans[t[i] - 'a']--; 将每个字符依次从数组中移除
}
for (int i = 0; i < 26; i++) {
if (ans[i] != 0) {
return false; //如果数组元素不为0,说明字符串不是异位词
}
}
return true;
}
};
两个数组的交集
题目描述
题意:给定两个数组,编写一个函数来计算它们的交集。
解题思路
方式一:通过集合实现
大体思路
-
通过分析题目可以得知输出结果中的每个元素都是唯一的,因此可以采用哈希表中的unordered_set进行存储
-
初始化两个集合 nums1_set,result_set,分别用于存储nums1中的元素以及交集元素
-
将数组nums1中方元素保存到集合中,依次遍历nums2中的元素在nums1_set中是否存在,如果存在将该元素插入到result_set中进行存储
-
将result_set转换为数组格式输出即可
时空复杂度
- 时间复杂度: O(n + m) m 是最后要把 set转成vector
- 空间复杂度: O(n)
方式二:通过数组实现
大致思路
- 由于数据范围可控,因此可以使用数组作为哈希表来判断元素交集,并将结果通过集合方式存储
- 初始化数组 hash_nums和集合result_set ,用于存储nums1中存在的元素,以及交集元素
- 遍历nums1中的所有元素,将存在的元素在hash_nums中对应的下标位置赋值为1
- 遍历nums2中的所有元素,查询元素在hash_nums中是否存在,如果存在插入结果集中存储
- 将result_set转换为数组格式输出即可
时空复杂度
- 时间复杂度: O(m + n)
- 空间复杂度: O(n)
代码实现
测试地址:https://leetcode.cn/problems/intersection-of-two-arrays/
集合实现:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
//将数组nums1转换为集合
unordered_set<int> nums1_set(nums1.begin(), nums1.end());
unordered_set<int> resut_set; //保存结果集并去重
for (int num : nums2) {
//遍历nums2中的元素,查找交集并插入结果集中
if (nums1_set.find(num) != nums1_set.end()) {
resut_set.insert(num);
}
}
//将集合转换为数组格式返回
return vector<int>(resut_set.begin(), resut_set.end());
}
};
数组实现:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set; //存放不重复的结果集
int hash_nums[1005] = {0}; //初始化为0
for (int num : nums1) {
hash_nums[num] = 1; //将nums1中出现的数组赋值为1
}
for (int num : nums2) {
if (hash_nums[num] == 1) { //已在hash数组中存储的元素加入到结果集
result_set.insert(num);
}
}
return vector<int>(result_set.begin(), result_set.end());
}
};
快乐数
题目描述
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
解题思路
总体思路:
由于题目中提到了会发生无限循环的情况,因此可以使用集合来判断是否重复出现了sum的情况,如果出现重复值就说明陷入了无线循环,直接return false,否则就继续循环直至sum为1为止。
代码实现
测试地址:https://leetcode.cn/problems/happy-number/
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> result;
while (1) {
int sum = getSum(n);
//循环终止条件,sum=1,找到快乐数
if (sum == 1) {
return true;
}
//如果sum已经出现过了,直接跳出
if (result.find(sum) != result.end()) {
return false;
} else {
//如果没有出现,加入到集合中存储
result.insert(sum);
}
//更新sum的值
n = sum;
}
}
};
两数之和
题目描述
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
解题思路
总体思路
数据结构选择思路:
- 通过分析题意可知,题目要求我们在数组中查询是否有两个值相加之和满足目标值的整数,因此可以采用哈希表的方式进行解题,即判断某个元素是否已经出现过了
- 因为我们需要得到数组元素值以及对应下标,因此可以使用哈希表的方式进行存储
代码实现:
- 初始化一个unordered_map,用于存放已经遍历过的数组元素及其下标
- 遍历数组元素,将目标值减去当前元素取得差值,然后在map中查找是否存在等于差值的元素,如果存在返回两数下标,如果不存在将当前元素值作为key下标作为value传入map中,继续遍历下一个元素
代码实现
测试地址:https://leetcode.cn/problems/two-sum/description/
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
// 创建一个 unordered_map,用来存储数组元素和对应的索引
unordered_map<int, int> map;
// 遍历 nums 数组
for (int i = 0; i < nums.size(); i++) {
// 使用 find 方法尝试在 map 中找到与当前元素互补的元素
// 即,我们需要的是某个数 x,使得 x + nums[i] = target
auto iter = map.find(target - nums[i]);
// 如果找到了这个互补元素
if (iter != map.end()) {
// 返回一个包含两个索引的向量
// iter->second 是互补元素的索引,i 是当前元素的索引
return {iter->second, i};
} else {
// 如果没有找到互补元素,将当前元素的值和索引插入到 map 中
// nums[i] 是键,i 是值
map.insert(pair<int, int>(nums[i], i));
}
}
// 如果没有任何两个数的和等于 target,返回一个空向量
return {};
}
};