15. 有效的字母异位
C++:
这里使用了哈希表的方法
先将传入的两个字符串的每一项读取到各自的数组中,然后判断数组的各项数值是否相等,如果相等就是有效的字母异位,不相等就不是
不过!!!代码随想录给出的代码有一点很值得学习一下:先将第一个字符串的字母统计到一个数组中,然后,在统计第二个字符串的时候,在原来的那个数组中做减法,那样只需要一个数组,在之后只需要统计,数组里是否有比0小的数,只要有就输出false!非常巧啊!
class Solution {
public:
bool isAnagram(string s, string t) {
int record[26] = {0};
for (int i = 0; i < s.size(); i++){
record[s[i] - 'a']++;
}
for (int i = 0; i < t.size(); i++){
record[t[i] - 'a']--;
}
for (int i = 0; i < sizeof(record)/sizeof(record[0]); i++){
if (record[i] != 0){
return false;
}
}
return true;
}
};
16. 两个数组的交集
C++:
这个题触碰到了我的一个大的知识上的漏洞,C++的容器和迭代器那部分的内容没学习呢,得补一补了!
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());
}
};
在
intersection
函数中,创建了一个unordered_set<int>
类型的result_set
对象,用于存放结果。使用unordered_set
是为了避免结果集中出现重复的元素。创建了一个
unordered_set<int>
类型的nums_set
对象,并使用nums1
容器的迭代器范围初始化它。这样做的目的是将nums1
中的元素放入nums_set
中,以便快速查找。使用
for
循环遍历nums2
容器中的每个元素,并对每个元素执行以下操作:a. 使用
nums_set.find(num)
在nums_set
中查找当前元素num
。b. 如果
find
操作返回的迭代器不等于nums_set.end()
,即找到了与nums2
中当前元素相等的元素,则将当前元素插入到result_set
中。注:
result_set.begin()
:这是unordered_set
类的成员函数,返回一个指向result_set
集合中第一个元素的迭代器。result_set.end()
:这也是unordered_set
类的成员函数,返回一个指向result_set
集合中最后一个元素之后位置的迭代器。vector<int>(result_set.begin(), result_set.end())
:这是vector
类的构造函数,它接受两个迭代器参数,表示一个范围,并将该范围内的元素复制到一个新的vector<int>
对象中。
result_set.begin()
是范围的起始迭代器,指向result_set
集合中第一个元素。result_set.end()
是范围的结束迭代器,指向result_set
集合中最后一个元素之后的位置。返回一个新的
vector<int>
对象,该对象包含了result_set
中的所有元素。这是通过使用vector
类的迭代器范围构造函数实现的。
按照代码随想录上的后记,立扣改了题目描述和后台测试数据,增添了数值的范围,所以使用数组也是可以的,那么就可以对上述的代码进行简单的修改
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重
int hash[1005] = {0}; // 默认数值为0
for (int num : nums1) { // nums1中出现的字母在hash数组中做记录
hash[num] = 1;
}
for (int num : nums2) { // nums2中出现话,result记录
if (hash[num] == 1) {
result_set.insert(num);
}
}
return vector<int>(result_set.begin(), result_set.end());
}
};
17. 快乐数
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
因为可能要无限循环,得到特别多的数,我们要在这特别多的数中间找到快速判断一个元素是否出现过,这个时候,就想到了哈希表
那么重点在于,如何去求解传入参数n的各位平方之和呢?
判断sum是否重复出现就可以使用unordered_set
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;
}
}
};
在这里需要重点说一下,这个
set.find(sum) != set.end()
这是一个条件表达式,用于判断set.find(sum)
返回的迭代器是否等于set.end()
,即是否找到了与sum
相等的元素。
- 如果
set.find(sum)
返回的迭代器不等于set.end()
,说明在set
中找到了与sum
相等的元素,条件成立,表达式的值为true
。- 如果
set.find(sum)
返回的迭代器等于set.end()
,说明在set
中未找到与sum
相等的元素,条件不成立,表达式的值为false
。
18. 两数之和
242. 有效的字母异位词 这道题目是用数组作为哈希表来解决哈希问题,349. 两个数组的交集 这道题目是通过set作为哈希表来解决哈希问题。
什么时候使用哈希法,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。
本题呢,我就需要一个集合来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。那么我们就应该想到使用哈希法了。
因为本题,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。
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++){
auto iter = map.find(target - nums[i]);
if (iter != map.end()){
return {iter->second, i};
}
map.insert(pair<int, int>(nums[i], i));
}
return {};
}
};
首先需要学习的是map数据结构的创建方式
std::unordered_map<int,int> map;
auto iter = map.find(target - nums[i]);
中的auto
的含义:
- 关键字
auto
被用于声明一个变量iter
,其类型是根据等号右侧的表达式自动推导得出的。在这种情况下,map.find(target - nums[i])
返回的是一个迭代器,其类型是std::unordered_map<int, int>::iterator
(或者是std::unordered_map<int, int>::const_iterator
)。因此,使用auto
关键字可以让编译器根据返回类型自动推导出iter
的类型,而不必手动指定迭代器的类型。- 使用
auto
关键字的好处是使代码更简洁,减少了重复的类型声明,同时也使代码更具灵活性和可读性。当我们不关心迭代器的具体类型时,使用auto
关键字可以更加简洁地编写代码。
map.find(target - nums[i])
返回的是一个迭代器,用于指向std::unordered_map
中的键值对。具体来说,它是std::unordered_map<int, int>::iterator
类型的迭代器,或者如果是在常量对象上调用的,则为std::unordered_map<int, int>::const_iterator
类型的迭代器。迭代器是一种用于访问容器中元素的对象,它可以指向容器中的任意一个元素,并且可以通过迭代器来访问该元素的值或进行修改。在这种情况下,
map.find(target - nums[i])
返回的迭代器指向了键值为target - nums[i]
的元素(如果存在的话),否则返回map.end()
,表示未找到。因此,
map.find(target - nums[i])
返回的是一个迭代器,用于在std::unordered_map<int, int>
中查找键值为target - nums[i]
的元素。
iter->second
是通过迭代器iter
访问键值对中的值部分的语法。在std::unordered_map
中,每个键值对都有两部分:键和值。键存储在first
成员中,而值存储在second
成员中。
pair<int, int>
是一个std::pair
类模板的实例化,用于表示包含两个值的有序对。具体来说,pair<int, int>
表示包含两个整数类型的值的有序对。在
map.insert(pair<int, int>(nums[i], i));
中,它表示要将一个有序对插入到std::unordered_map<int, int>
类型的map
中。这个有序对的第一个值是nums[i]
,第二个值是i
,即将当前数组元素nums[i]
作为键,将其索引i
作为值,插入到map
中。