给定两个字符串 s
和 t
,编写一个函数来判断 t
是否是 s
的字母异位词。
注意:若 s
和 t
中每个字符出现的次数都相同,则称 s
和 t
互为字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram" 输出: true
示例 2:
输入: s = "rat", t = "car" 输出: false
思路:
看到这道题, 首先想到的是我将两个字符串里面所有的字母全部存进一个哈希容器unordered_map<char, int> word;中, 然后在这个容器中遍历, 每个字母是否出现两次. 直到写完代码我才意识到, 一个字符串里不会只有不同的字符.
那么就用两个哈希容器分别来存取两个字符串里的内容, Key-Value对就分别考虑字符char和其出现的频次frequency吧.
简单构建完并且输入哈希表之后的代码:
class Solution {
public:
bool isAnagram(string s, string t) {
unordered_map<char, int> word_countS;
unordered_map<char, int> word_countT;
for(char words : s){
++word_countS[words];
}
for(char wordt : t){
++word_countT[wordt];
}
for(char word : longer(s, t)){
if(word_countS.count(word) != word_countT.count(word) )
return false;
}
return true;
}
// 比较更长的字符串
string longer(string s, string t){
return s = s.compare(t) >= 0 ? s : t;
}
}
我以为能运行成功了, 结果:
百思不得其解, 最后还是妥协给了ChatGPT, 一问之下才发现原来是选择较长的子序列中, compare函数的使用问题:
使用了
s.compare(t) >= 0
来比较字符串的大小,但这并不是你想要的比较字符串长度的方式。std::string::compare
函数用于比较字符串的字典顺序,而不是长度。
结果我竟然忘记了string也能够使用成员函数"size()"来返回大小....
修改后的代码(AC):
class Solution {
public:
bool isAnagram(string s, string t) {
unordered_map<char, int> word_countS;
unordered_map<char, int> word_countT;
for(char words : s){
++word_countS[words];
}
for(char wordt : t){
++word_countT[wordt];
}
for(char word : longer(s, t)){
if(word_countS[word] != word_countT[word] )
return false;
}
return true;
}
string longer(string s, string t){
return s = s.size() >= t.size() ? s : t;
}
};
对Carl代码的思考:
Carl使用一个数组来充当哈希表, 数组索引即为字符在英文字母的位置, 同时也是英文字母的键, 数组存取的内容是英文字母出现的次数, 先存进一个字符串的内容, 然后再通过另一个字符串的内容来让数组减去, 这样来说只需要一个哈希表就能够解决问题. 如果用我的map容器应该也能解决, 也就是map容器来充当这个数组, 其实本质都是相同的.
class Solution {
public:
bool isAnagram(string s, string t) {
int recode[26] = {0};
for(char word : s){
if(word - 'a' >= 0 && word - 'a' < 26){
recode[word - 'a']++;
}
}
for(char word : t){
if(word - 'a' >= 0 && word - 'a' < 26){
recode[word - 'a']--;
}
}
for(int i : recode){
if(i != 0) return false;
}
return true;
}
};
349. 两个数组的交集
给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出:[9,4] 解释:[4,9] 也是可通过的
建议:本题就开始考虑 什么时候用 set 什么时候用数组,本题其实是使用set的好题,但是后来力扣改了题目描述和 测试用例,添加了 0 <= nums1[i], nums2[i] <= 1000 条件,所以使用数组也可以了,不过建议大家忽略这个条件。 尝试去使用set。
题目链接/文章讲解/视频讲解:代码随想录
思路:
看到返回交集问题, 首先想到刚刚才学的set容器的set_intersection()成员函数, 但是真的太难用了, 打消了使用了念头. 然后就想着遍历数组nums1和数组nums2里的数据, 把相同的数字存入set容器中. 然后暴力搜索找到相同内容送入set容器去重, 最后返回一个vector<int>容器复制set容器里的内容, 时间复杂度是O(n²)
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> common_num;
for(int i : nums1){
for(int j : nums2){
if(i == j) common_num.insert(i);
}
}
return vector<int>(common_num.begin(), common_num.end());
}
};
完成代码的时候遇到了很多挫折, 最主要的原因是对STL容器的不熟悉, 比如最后返回的是vector类型, 可是我的内容定义在set容器里.
代码中的返回可以这样定义一个容器, 把set容器的首尾迭代器传入就可以定义一个与set容器内容相同的vector容器来返回了.
Carl的代码:
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());
}
};
定义两个unordered_set容器: result_set和nums_set, 先将nums1复制给nums_set, 然后遍历nums2, 再通过键来查找nums_set里的元素, 将相同的元素插入到result_set中, 最后返回.这样看来其实都是遍历比较, 但是unordered_set容器的查找时间是O(1), 远远快于数组的查找. 哈希表真是一个神奇的数据结构!
202. 快乐数
编写一个算法来判断一个数 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
建议:这道题目也是set的应用,其实和上一题差不多,就是 套在快乐数一个壳子
题目链接/文章讲解:代码随想录
思路:
见到的时候还以为是找规律, 实在想不出来就去看Carl的思路了, 结果竟然是通过循环来判定.判定思路就是计算一次每个数字的平方和然后插入到unordered_set容器中, 遍历插入后的容器, 如果能找到重复的数字或者这个平方和是1就停止.
代码如下:
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> nums;
while(1){
int sum = getsum(n);
if(sum == 1) return true;
if(nums.find(sum) != nums.end()){
return false;
}
else{
nums.insert(sum);
}
n = sum;
}
}
};
1. 两数之和
建议:本题虽然是 力扣第一题,但是还是挺难的,也是 代码随想录中 数组,set之后,使用map解决哈希问题的第一题。
建议大家先看视频讲解,然后尝试自己写代码,在看文章讲解,加深印象。
题目链接/文章讲解/视频讲解:代码随想录
思路:
暴力快排, 找到两个相加等于target的值就插入下标.但是我这里浪费了unordered_map容器的内容, 对哈希表的使用还是不够好, 还是得继续多学多复习.
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> count_num;
for(int i = 0; i< nums.size(); i++){
for(int j = i + 1; j< nums.size(); j++){
if(nums[i] + nums[j] == target){
count_num.insert(make_pair(i,j));
}
}
}
vector<int> result;
for(auto pair : count_num){
result.push_back(pair.first);
result.push_back(pair.second);
}
return result;
}
};
Carl的代码:
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 {};
}
};
Carl的代码还没有仔细看过..两数之和准备了一个线性的思路, 这里还没有完成, 明天再来吧....
今天的状态不是很好, 明天调整一下再战哈希表, 加油!