目录
给定两个字符串 s
和 t
,编写一个函数来判断 t
是否是 s
的字母异位词。
注意:若 s
和 t
中每个字符出现的次数都相同,则称 s
和 t
互为字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram" 输出: true
示例 2:
输入: s = "rat", t = "car" 输出: false
set集合
set好慢。。。
class Solution {
public:
bool isAnagram(string s, string t) {
multiset<int> ss;
multiset<int> tt;
int size_s = s.size();
int size_t = t.size();
for (int i = 0; i < size_s; i++)
{
ss.insert(s[i]);
}
for (int i = 0; i < size_t; i++)
{
tt.insert(t[i]);
}
for (int i = 'a'; i <= 'z'; i++)
{
if (ss.count(i) != tt.count(i))
{
return false;
}
}
return true;
}
};
数组
比set快多了
class Solution {
public:
bool isAnagram(string s, string t) {
int ss[26] = {0};
int tt[26] = {0};
for (int i = 0; i < s.size(); i++)
{
ss[s[i] - 'a']++;
}
for (int i = 0; i < t.size(); i++)
{
tt[t[i] - 'a']++;
}
for (int i = 0; i < 26; i++)
{
if (ss[i] != tt[i])
{
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可以去重
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> t;
vector<int> res;
for (int i = 0; i < nums1.size(); i++)
{
t.insert(nums1[i]);
}
for (int i = 0; i < nums2.size(); i++)
{
if (t.count(nums2[i]) != 0)
{
res.push_back(nums2[i]);
t.erase(nums2[i]); //删除当前数,避免答案重复
}
}
return res;
}
};
202. 快乐数
编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
。
示例 1:
输入:n = 19 输出:true 解释: 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1
示例 2:
输入:n = 2 输出:false
若n不是快乐数时会陷入无限的循环,即会重复计算结果。所以本题的关键在于判断结果是否有重复的存在。
class Solution {
public:
int getSum(int n)
{
int res = 0;
while (n)
{
int t = n % 10;
res += t * t;
n /= 10;
}
return res;
}
bool isHappy(int n) {
unordered_set<int> res;
while (1)
{
int sum = getSum(n);
if (sum == 1)
{
return true;
}
if (res.count(sum) != 0) //找到重复计算结果
{
return false;
}else
{
res.insert(sum);
}
n = sum;
}
}
};
1. 两数之和
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6 输出:[1,2]
用map的key来记录数组元素,value来记录数组下标。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map <int, int> map;
for (int i = 0; i < nums.size(); i++)
{
auto t = map.find(target - nums[i]);
if (t != map.end())
{
return {i, t->second};
}
map[nums[i]] = i; //插入
}
return {};
}
};
454. 四数相加 II
给你四个整数数组 nums1
、nums2
、nums3
和 nums4
,数组长度都是 n
,请你计算有多少个元组 (i, j, k, l)
能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
示例 1:
输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2] 输出:2 解释: 两个元组如下: 1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0 2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
和上一题差不多,可以先遍历前两个数组,将它们元素的和保存到map的key中,value记录不同和的个数。之后再遍历后两个数组的和。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> map; //key存放1,2数组元素的和,value存放和出现的个数
for (int i = 0; i < nums1.size(); i++)
{
for (int j = 0; j < nums2.size(); j++)
{
map[nums1[i] + nums2[j]]++;
}
}
int cnt = 0;
for (int i = 0; i < nums3.size(); i++)
{
for (int j = 0; j < nums4.size(); j++)
{
auto t = map.find(0 - (nums3[i] + nums4[j]));
if (t != map.end())
{
cnt += t->second;
}
}
}
return cnt;
}
};
383. 赎金信
给你两个字符串:ransomNote
和 magazine
,判断 ransomNote
能不能由 magazine
里面的字符构成。
如果可以,返回 true
;否则返回 false
。
magazine
中的每个字符只能在 ransomNote
中使用一次。
示例 1:
输入:ransomNote = "a", magazine = "b" 输出:false
示例 2:
输入:ransomNote = "aa", magazine = "ab" 输出:false
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int res[26] = {0};
for (int i = 0; i < magazine.size(); i++)
{
res[magazine[i] - 'a']++;
}
for (int i = 0; i < ransomNote.size(); i++)
{
int j = ransomNote[i] - 'a';
if (res[j] != 0)
{
res[j]--;
}else
{
return false;
}
}
return true;
}
};
15. 三数之和
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
本题使用哈希表求解比较困难,所以采用双指针法来求解。
大题思路:
去重:
因为本题要求答案三元组中不可以有重复的元素,如{-1,-1,2}和{2,-1,-1},但可以有三元组组内的元素重复,如{0,0,0}。
在我们已经从小到大排好序的前提下,我们应该使用nums[i]与nums[i+1]比较是否相等,还是比较nums[i]与nums[i-1]是否相等?
若我们使用这个去重逻辑则当出现类似{-1,-1,2}这样的答案三元组时,此时i指向-1这个元素,因为i与该元素的下一个元素相比较,发现相等则会跳过这个三元组,i此时会指向2这个元素。这样的去重逻辑会将有重复元素的三元组全部去重,不符合题目要求。所以我们应当采用第二种去重逻辑。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int> > res; //二维数组存储结果
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) //通过遍历a来确定left和right
{
if (nums[i] > 0) //因为数组此时是从小到大的,若当前的nums[i]比0还大,则和一定>0
{
return res;
}
if (i > 0 && nums[i] == nums[i - 1]) //对a进行去重
{
continue;
}
int left = i + 1;
int right = nums.size() - 1;
while (left < right) //因为三元组中下标不可以相同所以不是<=
{
if (nums[i] + nums[left] + nums[right] > 0)
{
right--;
}else if (nums[i] + nums[left] + nums[right] < 0)
{
left++;
}else
{
res.push_back(vector<int>{nums[i], nums[left], nums[right]});
//对left和right去重(和a那里不大一样)
while (left < right && nums[left] == nums[left + 1])
{
left++;
}
while (left < right && nums[right] == nums[right - 1])
{
right--;
}
left++;
right--;
}
}
}
return res;
}
};
18. 四数之和
和上一题一样
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int> > res;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++)
{
//这里与三数之和不大一样,因为此时的target可能为负数,所以如:target=-10时,而{-4,-3,-2,-1}不能因为-4>-10就跳过
if (nums[i] > target && target >= 0)
{
break;
}
if (i > 0 && nums[i] == nums[i - 1])
{
continue;
}
for(int j = i + 1; j < nums.size(); j++)
{
if (nums[j] > target - nums[i] && target >= 0)
{
break;
}
if (j > i + 1 && nums[j] == nums[j - 1])
{
continue;
}
int left = j + 1;
int right = nums.size() - 1;
while (left < right)
{
if ((long) nums[i] + nums[j] + nums[left] + nums[right] > target)
{
right--;
}else if ((long) nums[i] + nums[j] + nums[left] + nums[right] < target)
{
left++;
}else
{
res.push_back(vector<int>{nums[i], nums[j], nums[left], nums[right]});
while (right > left && nums[right] == nums[right - 1])
{
right--;
}
while (right > left && nums[left] == nums[left + 1])
{
left++;
}
right--;
left++;
}
}
}
}
return res;
}
};