2024/4/23 代码随想录Day 6: 202. 快乐数 1. 两数之和
2024/4/23 代码随想录Day 7:454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和
202. 快乐数
set的应用
题目链接 202 编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
第一次提交
三种有趣的做法
- Hash
- Fast-slow 检测环
- 数学推到寻找环
c++ version
1.Hash
class Solution {
public:
int happy(int n) {
int res = 0;
while (n > 0) {
// cout<< n<< endl;
res += (n % 10) * (n % 10);
n /= 10;
}
return res;
}
bool isHappy(int n) {
// cout<< happy(n)<<endl;
// return true;
unordered_set<int> visited;
while (n != 1) {
if (visited.count(n)) return false;
visited.insert(n);
n = happy(n);
}
return true;
}
};
- Fast-slow index
class Solution {
public:
int happy(int n) {
int res = 0;
while (n > 0) {
// cout<< n<< endl;
res += (n % 10) * (n % 10);
n /= 10;
}
return res;
}
bool isHappy(int n) {
// cout<< happy(n)<<endl;
// return true;
unordered_set<int> visited;
while (n != 1) {
if (visited.count(n)) return false;
visited.insert(n);
n = happy(n);
}
return true;
}
};
Python Version
1.Hash
divmod 函数
class Solution:
def happy(n):
res = 0
while n > 0:
n, digit = divmod(n, 10)
res += digit**2
return res
def isHappy(self, n: int) -> bool:
seen = set()
while n != 1 and n not in seen:
seen.add(n)
n = happy(n)
return n == 1
1.Fast-Slow
class Solution:
def happy(self, n):
res = 0
while n > 0:
n, digit = divmod(n, 10)
res += digit**2
return res
def isHappy(self, n: int) -> bool:
slow_runner = n
fast_runner = self.happy(n)
while fast_runner!= 1 and slow_runner != fast_runner:
slow_runner = self.happy(slow_runner)
fast_runner = self.happy(self.happy(fast_runner))
return fast_runner == 1
1. 两数之和
题目链接 1 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
[随想录]
第一次提交
C++ Version
使用hash map
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> map;
vector<int> res= {};
for (int i = 0; i < nums.size(); i++) {
if (map.count(target - nums[i])) {
res.push_back(map[target-nums[i]]);
res.push_back(i);
break;
} else {
map[nums[i]] = i;
}
}
return res;
}
};
hash 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++) {
// 遍历当前元素,并在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 {};
454.四数相加II
四数相加
题目链接 454 给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
第一次提交
不需要去重所以相对简单
c++ version
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> map;
for (int i = 0; i < nums1.size(); i++){
for (int j = 0; j < nums2.size(); j++){
if (map.count(nums1[i] + nums2[j])) {
map[nums1[i] + nums2[j]]++;
} else {
map[nums1[i] + nums2[j]] = 1;
}
}
}
int res = 0;
for (int i = 0; i < nums3.size(); i++){
for (int j = 0; j < nums4.size(); j++){
if (map.count(-nums3[i] - nums4[j])) {
res += map[-nums3[i] - nums4[j]];
}
}
}
return res;
}
};
Python Version
class Solution(object):
def fourSumCount(self, nums1, nums2, nums3, nums4):
# 使用字典存储nums1和nums2中的元素及其和
hashmap = dict()
for n1 in nums1:
for n2 in nums2:
if n1 + n2 in hashmap:
hashmap[n1+n2] += 1
else:
hashmap[n1+n2] = 1
# 如果 -(n1+n2) 存在于nums3和nums4, 存入结果
count = 0
for n3 in nums3:
for n4 in nums4:
key = - n3 - n4
if key in hashmap:
count += hashmap[key]
return count
383. 赎金信
题目链接 383 给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
第一次提交
比较简单
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int hash[26] = {0};
for (char c : magazine) {
hash[c - 'a']++;
}
for (char c: ransomNote){
hash[c - 'a']--;
if (hash[c - 'a'] < 0) 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 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
第一次提交
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
vector<int> tri;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size() && nums[i] <= 0; i++) { // 剪枝
if (i > 0 && nums[i] == nums[i - 1])
continue; // 去重
int left = i + 1, right = nums.size() - 1;
while (left < right && nums[i] + nums[left] <= 0) { // 剪枝
if (nums[left] + nums[right] + nums[i] == 0) {
tri.push_back(nums[i]);
tri.push_back(nums[left]);
tri.push_back(nums[right]);
res.push_back(tri);
tri.clear();
left++;
right--;
while (nums[left] == nums[left - 1] && left < right)
left++; // 去重
while (nums[right] == nums[right + 1] && left < right)
right--; // 去重
continue;
}
if (nums[left] + nums[right] + nums[i] < 0) {
left++;
continue;
}
if (nums[left] + nums[right] + nums[i] > 0) {
right--;
continue;
}
}
}
return res;
}
};
这回第一次写就很优雅
18. 四数之和
题目链接 18 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
Trick: 如何处理超过int范围:(long)a+b
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
for (int k = 0; k < nums.size(); k++) {
if (nums[k] > target && nums[k] >= 0)
break;//剪枝
if (k > 0 && nums[k] == nums[k - 1])
continue;//去重
for (int i = k + 1; i < nums.size(); i++) {
if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0)
break;//剪枝
if (i > k + 1 && nums[i] == nums[i - 1])
continue;//去重
int left = i + 1, right = nums.size() - 1;
while (left < right &&
!((long)nums[k] + nums[i] + nums[left] > target &&
target >= 0 && nums[left] >= 0)) {//剪枝
if ((long)nums[k] + nums[i] + nums[left] + nums[right] ==
target) {
res.push_back(vector<int>{nums[k], nums[i], nums[left],
nums[right]});
left++;
right--;
while (nums[left] == nums[left - 1] && left < right)//注意这里的停止条件,容易死循环
left++;//去重
while (nums[right] == nums[right + 1] && left < right)//注意这里的停止条件,容易死循环
right--;//去重
continue;
}
if ((long)nums[k] + nums[i] + nums[left] + nums[right] <
target) {
left++;
continue;
}
if ((long)nums[k] + nums[i] + nums[left] + nums[right] >
target) {
right--;
continue;
}
}
}
}
return res;
}
};