给你四个整数数组 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
示例 2:
输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
输出:1
提示:
n == nums1.length
n == nums2.length
n == nums3.length
n == nums4.length
1 <= n <= 200
-228 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 228
我的思路:
四数相加:
[{} , {} ]
两数相加使用的是减法,四数应该也是
nums1[1] nums2[-2] num3[-1] nums4[0]
map里面存的是1,2的(值加次数):1,-1
循环遍历nums3,num4:-1 map:0,-1 map.length=0 return temp
但是这样的话,它怎么进行第二轮呢?第一轮就把map=0了
改变思路:
map:-1 0 0 1
如果想要nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
那么就需要num3+num4=
1或者0或者0或者-1
nums3+nums4 = -1 ans++ | 1 ans++ | 2 4
ans = 2
所以num1加num2放在map里面,遍历num3和num4求sum,map里面是否有-sum
我的代码:
function fourSumCount(nums1: number[], nums2: number[], nums3: number[], nums4: number[]): number {
let addMap : Map = new Map();
let ans : number = 0;
// 遍历num1,num2
for(let i of nums1){
for(let j of nums2){
// 存储在map里面,如果map没有就新建一个,如果有的话键加一
let sum = i + j ;
// 有sum这个键
if(addMap.has(sum)){
// 得到对应的值(次数)
addMap.set(sum , addMap.get(sum) + 1);
}else {
addMap.set(sum , 1);
}
}
}
// 遍历num3,num4
for(let i of nums3){
for(let j of nums4){
let sum = - ( i + j ) ;
// 如果说addMap里面存在-sum,就让它对应的次数-1
if(addMap.has(sum)){
ans ++;
}
}
}
return ans;
};
答案错误!!
nums1 =
[-1,-1]
nums2 =
[-1,1]
nums3 =
[-1,1]
nums4 =
[1,-1]
map:-2 0 -2 0
1+1+1 = 3
如果只是简单的ans++就会损失一部分的答案
-1+1 = 0 ans=2
-1+ -1 = -2 ans += 2 = 4
在进入map的时候我们应该是值加次数的形式,在ans加的时候应该加的是次数
修改代码:
function fourSumCount(nums1: number[], nums2: number[], nums3: number[], nums4: number[]): number {
let addMap : Map = new Map();
let ans : number = 0;
// 遍历num1,num2
for(let i of nums1){
for(let j of nums2){
// 存储在map里面,如果map没有就新建一个,如果有的话键加一
let sum = i + j ;
// 有sum这个键
if(addMap.has(sum)){
// 得到对应的值(次数)
addMap.set(sum , addMap.get(sum) + 1);
}else {
addMap.set(sum , 1);
}
}
}
// 遍历num3,num4
for(let i of nums3){
for(let j of nums4){
let sum = - ( i + j ) ;
// 如果说addMap里面存在-sum,就让它对应的次数-1
if(addMap.has(sum)){
ans += addMap.get(sum);
}
}
}
return ans;
};
总结:
四数相加就体现了map的好处,受到之前两数相加的启发,我选择了先计算前面两个数进入map,后遍历后两个数求和看看是否存在与map当中,如果存在我直接ans++,但是第一次提交的时候答案错误了,ans++代表的是map里面只有一个sum,但是有的时候可能会有多个,所以正确方法一个是将次数也要存起来,直接用ans加次数就可以了。
s(t[j])){
return false;
}else {
// 如果有相同的,我们直接把map里面的对应的次数减1,全部移除了就证明两个是相等的
map.set(t[j] , (map.get(t[j]) - 1 ))
// 如果值(出现次数为0),delete这个键
if(map.get(t[j]) === 0){
map.delete(t[j]);
}
}
}
return map.size === 0;
};
总结:这道题考的是对map的敏感度以及map的方法的使用,利用map记录下s字符以及出现的次数,遍历t字符,如果s字符里面有t的其中一个字符,值就要对应减一,当减到值为0的时候,就要消除键。如果最后map的长度等于0就是相等,不等于就是不相同
# 5.15 哈希表合集---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] 也是可通过的
我的思路:
返回交集
nums1 = [1,2,2,1], nums2 = [2,2]
map [{1 , 1} , { 2 , 2}]
map.has
解决问题:去重问题 =>set
我的代码:
function intersection(nums1: number[], nums2: number[]): number[] {
// 存储的set
let set = new Set();
let set2 = new Set();
let ans = [];
let i = 0 ;
// 遍历数组当set当中
for(let i = 0 ; i < nums1.length ; i++){
set.add(nums1[i]);
}
for(let i = 0 ; i < nums2.length ; i++){
set2.add(nums2[i]);
}
// 遍历set2判断set2的值set1是否有
set2.forEach((item) => {
if(set.has(item)){
ans[i] = item;
i++;
}
})
return ans;
};
虽然我的代码可以成功解答,但是从时间来看耗费的时长很大,而且耗费的空间也很大。
看了一下其他人的代码对我的代码进行了更新迭代:
ts语法+答案数组最开始为set后面转化为数组
let resSet : Set = new Set(nums1);//生成有nuns1的数字且不相同的set
let ansSet : Set = new Set();
for( let i of nums2){
if(resSet.has(i)){
ansSet.add(i);
}
}
return Array.from(ansSet);
注意!
ts声明的方式:
let resSet : Set = new Set(nums1);
转化为数组的方式:
Array.from(ansSet);
总结:本道题考的是对set的敏感度,我们知道set最大的优点就是不含重复的值,这对于本道题目有大大滴好处,先初始化一个对比set,后nums2是否在set中,在处理nums2进答案数组的时候,也是为了去重,我们事先将答案数组转化为set,后转化为数组的。
1. **new Set()** : 创建一个新的 Set 对象。
2. **add(value)** : 添加一个指定的值到 Set 对象中。
3. **delete(value)** : 从 Set 对象中删除一个指定的值。
4. **has(value)** : 判断 Set 对象中是否包含一个指定的值。
5. **clear()** : 清除 Set 对象中的所有元素。
6. **forEach(callback[, thisArg])** : 对 Set 对象中的每一个值应用一个回调函数。
7. **values() / keys()** : 返回一个新的迭代器对象,包含 Set 对象中的所有值(因为 Set 对象中的值是唯一的,所以 keys 和 values 返回的结果相同)。
8. **entries()** : 返回一个新的迭代器对象,包含 Set 对象中的所有成员的键值对数组。
9. **size** : 返回 Set 对象中的值的数量。
# 5.16 哈希表合集---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 = 2
sum = 4
sum = 16
sum = 1 + 36 = 37
sum = 9 + 49 = 58
sum = 25 + 64 = 89
sum = 64 + 81 = 145
sum = 1 + 14 + 25 = 40
sum = 16 + 0 = 16
与第二个sum相等了,一直循环->return false
所以map一直存存存,得到的数要与map里面的sum进行比较,如果map里面有sum就证明又要重新循环
这个时候直接返回false
我的思路:
先一直循环,将sum存入set当中,然后将sum的数重新平方后相加,如此循环。一直到出现原来的sum或者出现sum=1的时候为止
**出现的错误:**
它是一个数字,但是进行相加要把它拆分为数组:
// 数字转化为字符并用split分割得到数组
let number = n.toString().split('');;
数组里面就是字符串,一定在相乘的时候要转化为数字
for(let item of number){
sum += Number(item) * Number(item);
}
**我的代码:**
function isHappy(n: number): boolean {
const set = new Set();
let sum = n;
while(sum != 1){
sum = getSum(sum);
if(set.has(sum)){
return false;
}else {
set.add(sum);
}
}
return true;
};
function getSum( n : number ) : number {
// 数字转化为字符并用split分割得到数组
let number = n.toString().split(‘’);;
let sum = 0 ;
for(let item of number){
sum += Number(item) * Number(item);
}
return sum;
}
**总结:**
最开始拿到这道题,我一头雾水,无限暴力循环???一直没有1怎么办。然后我就开始遍历实例2,发现它一直没有1的原因其实是一直在循环,这便是一个很大的突破口,如果sum之前已经出现了,那么一定会一直循环,便是解题方法。
# 5.17 哈希表合集---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`
**示例 1:**
输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:
**示例 2:**
输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
输出:1
**提示:**
- `n == nums1.length`
- `n == nums2.length`
- `n == nums3.length`
- `n == nums4.length`
- `1 <= n <= 200`
- `-228 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 228`
**我的思路:**
四数相加:
[{} , {} ]
两数相加使用的是减法,四数应该也是
nums1[1] nums2[-2] num3[-1] nums4[0]
map里面存的是1,2的(值加次数):1,-1
循环遍历nums3,num4:-1 map:0,-1 map.length=0 return temp
但是这样的话,它怎么进行第二轮呢?第一轮就把map=0了
**改变思路:**
map:-1 0 0 1
如果想要nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
那么就需要num3+num4=
1或者0或者0或者-1
nums3+nums4 = -1 ans++ | 1 ans++ | 2 4
ans = 2
所以num1加num2放在map里面,遍历num3和num4求sum,map里面是否有-sum
**我的代码:**
function fourSumCount(nums1: number[], nums2: number[], nums3: number[], nums4: number[]): number {
let addMap : Map
let ans : number = 0;
// 遍历num1,num2
for(let i of nums1){
for(let j of nums2){
// 存储在map里面,如果map没有就新建一个,如果有的话键加一
let sum = i + j ;
// 有sum这个键
if(addMap.has(sum)){
// 得到对应的值(次数)
addMap.set(sum , addMap.get(sum) + 1);
}else {
addMap.set(sum , 1);
}
}
}
// 遍历num3,num4
for(let i of nums3){
for(let j of nums4){
let sum = - ( i + j ) ;
// 如果说addMap里面存在-sum,就让它对应的次数-1
if(addMap.has(sum)){
ans ++;
}
}
}
return ans;
};
**答案错误!!**
nums1 =
[-1,-1]
nums2 =
[-1,1]
nums3 =
[-1,1]
nums4 =
[1,-1]
map:-2 0 -2 0
1+1+1 = 3
如果只是简单的ans++就会损失一部分的答案
-1+1 = 0 ans=2
-1+ -1 = -2 ans += 2 = 4
在进入map的时候我们应该是值加次数的形式,在ans加的时候应该加的是次数
**修改代码:**
function fourSumCount(nums1: number[], nums2: number[], nums3: number[], nums4: number[]): number {
let addMap : Map
let ans : number = 0;
// 遍历num1,num2
for(let i of nums1){
for(let j of nums2){
// 存储在map里面,如果map没有就新建一个,如果有的话键加一
let sum = i + j ;
// 有sum这个键
if(addMap.has(sum)){
// 得到对应的值(次数)
addMap.set(sum , addMap.get(sum) + 1);
}else {
addMap.set(sum , 1);
}
}
}
// 遍历num3,num4
for(let i of nums3){
for(let j of nums4){
let sum = - ( i + j ) ;
// 如果说addMap里面存在-sum,就让它对应的次数-1
if(addMap.has(sum)){
ans += addMap.get(sum);
}
}
}
return ans;
};
**总结:**
四数相加就体现了map的好处,受到之前两数相加的启发,我选择了先计算前面两个数进入map,后遍历后两个数求和看看是否存在与map当中,如果存在我直接ans++,但是第一次提交的时候答案错误了,ans++代表的是map里面只有一个sum,但是有的时候可能会有多个,所以正确方法一个是将次数也要存起来,直接用ans加次数就可以了。