202. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 如果这个过程 结果为 1,那么这个数就是快乐数。 如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
输入: n = 19
输出: true
解释: 12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。
解题思路:给你一个n,最后就两种结果一个是返回的是1,一个是陷入循环(出现了已经出现的结果)。
/**
* @param {number} n
* @return {boolean}
*/
var isHappy = function(n) {
let res = new Map()
const sum = (n) => {
let sum = 0
while(n){
sum += (n%10) ** 2 // 从最后一位数往前算
n = Math.floor(n / 10)
}
return sum
}
while(true){
if(res.has(n)) return false
if (n === 1) return true
res.set(n, 1)
n = sum(n)
}
};
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,
请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
解题思路1:暴力for循环
解题思路2: 我们遍历到数字a时,用target减去a就会得到b,若b存在于哈希表中,我们就可以直接返回结果了。若 b不存在,那么我们需要将a存入哈希表,好让后续遍历的数字使用。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
// var twoSum = function(nums, target) {
// let map = new Map();
// for(let i = 0;i < nums.length;i++){
// for(let j = i+1;j<nums.length;j++){
// let sum = nums[i] + nums[j]
// map.set(sum,[i,j])
// }
// }
// return map.get(target)
// };
var twoSum = function(nums, target) {
let map = new Map();
for(let i = 0, len = nums.length; i < len; i++){
if(map.has(target - nums[i])){
return [map.get(target - nums[i]), i];
}else{
map.set(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
输入: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
我一开始想法是先放第一个数组a的一个数字,值作为key下标作为vlaue,然后找后面三个数组的三个成员加起来等于sum,sum作为key,各自index作为value。然后看-sum是否在map中,在的话就返回。
上面想法是有瑕疵的,不如先考虑a,b两个组,求其中两个数字之后(sum为key,出现次数为value)。再考虑c,d两个其中两个元素的和sum2,如果-sum2存在map中,就说明这就是其中一个结果。
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @param {number[]} nums3
* @param {number[]} nums4
* @return {number}
*/
var fourSumCount = function(nums1, nums2, nums3, nums4) {
let map = new Map();
let count = 0;
for(const n1 of nums1){
for(const n2 of nums2){
const sum = n1 + n2;
map.set(sum, (map.get(sum) || 0) + 1)
}
}
for(const n3 of nums3){
for(const n4 of nums4){
const sum2 = n3 + n4;
count += (map.get(0 - sum2) || 0)
}
}
return count
};
383. 赎金信
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
输入: ransomNote = "aa", magazine = "aab"
输出: true
/**
* @param {string} ransomNote
* @param {string} magazine
* @return {boolean}
*/
var canConstruct = function(ransomNote, magazine) {
// 先设置26个字母的数组,字母出现一次就+1
// 返回的字典没有负号
let map = new Array(26).fill(0);
let base = 'a'.charCodeAt(); // a的ascall码
for(let i of magazine){
map[i.charCodeAt() - base]++
}
for(let j of ransomNote){
map[j.charCodeAt() - base]--
if(map[j.charCodeAt() - base] < 0){//如果数组出现符号
return false
}
}
return true
};
15. 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,
使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
输入: nums = [-1,0,1,2,-1,-4]
输出: [[-1,-1,2],[-1,0,1]]
哈希解法:两层for循环就可以确定 a 和b 的数值了,可以使用哈希法来确定 0-(a+b) 是否在 数组里出现过,其实这个思路是正确的,但是我们有一个非常棘手的问题,就是题目中说的不可以包含重复的三元组,比如:[1,0,-1,-1]。
双指针解法:
主要这题目有去重问题:
a去重:if(i>0 && nums[i]=nums[i-1]) continue
b,c去重:
while (L<R && nums[L] == nums[L+1]) L++;
while (L<R && nums[R] == nums[R-1]) R--;
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
let len = nums.length;
let res = [];
// 如果数组元素连三个都没有直接返回[]
if(len < 3) return [];
nums.sort((a, b) => a - b);
for(let i = 0;i < len-2; i++){
if(nums[i] > 0) break;//最小的数字都大于0了,直接跳出整个循环
// a去重 [0,0,-1,-1,-1,1],[-1,0,0,0,1]
// [-1,-1,2]只找了一次
if(i > 0 && nums[i] == nums[i-1]) continue;
let L = i+1;
let R = len-1;
while(L < R){
//虽然里面还有两个循环,但是整体的L和R移动的时间内复杂度还是o(n)
const sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
res.push([nums[i],nums[L],nums[R]]);
// b,c 去重 [-4,2,2,2,2]
while (L<R && nums[L] == nums[L+1]) L++; // 去重
while (L<R && nums[R] == nums[R-1]) R--; // 去重
L++;
R--;
}
else if (sum < 0) L++;
else if (sum > 0) R--;
}
}
return res
};
18. 四数之和
输入: nums = [1,0,-1,0,-2,2], target = 0
输出: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
这题目target不固定不一定是0,解题思路还是和上面三数求和一样但是多了一个j循环,感觉像是四个循环(两个for两个while)
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function(nums, target) {
let res = [];
let len = nums.length
if(len < 4) return [];
nums.sort((a, b) => a - b);
for(let i = 0;i < len-3;i++){
// 去重i
if(i > 0 && nums[i] === nums[i-1]) continue;
for(let j = i + 1; j < len - 2; j++) {
// 去重j
if(j > i + 1 && nums[j] === nums[j - 1]) continue;
let L = j+1;
let R = len - 1;
while(L < R){
let sum = nums[i] + nums[j] + nums[L] + nums[R];
if(sum === target){
res.push([nums[i],nums[j],nums[L],nums[R]]);
while(L < R && nums[L] === nums[L + 1]) L++;
while(L < R && nums[R] === nums[R - 1]) R--;
L++;
R--;
}
else if (sum < target) L++;
else if (sum > target) R--;
}
}
}
return res;
};