1. 两数之和
1. 两数之和 找数组内,两个元素值的和=target的数的下标
用
Map来存遍历过的key: 元素值``value: 下标,遍历数组,计算它和target的差,找Map中有没有:
- 有:返回下标
- 没有:加入
Map中继续找
失散的母子们:一群人中有几对母子,警察一个一个问他们要找的谁,用一张表存每个人的信息和要找的人,首先看表里有没有要找的那个人,如果没有就把他要找的人和信息记下来,看后面会不会有人找
用map映射
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) { // 使用map集合key:值,value:下标
let map = new Map()
for (let i = 0; i < nums.length; i++) { // 遍历数组
let sub = target - nums[i] // 计算满足条件的差值
if (map.has(sub)) return [map.get(sub), i] // 如果之前遍历过的有,返回下标
else {
map.set(nums[i], i) // 没有就加入set(k, v)存入map
}
}
return []
};
454. 四数相加 II
454. 四数相加 II
四个独立的数组,求有几个A[i] + B[j] + C[k] + D[l] = 0,即a + b + c + d = 0
- 定义一个
map存key: a+b,value: a+b出现过几次 - 遍历A和B,统计两数组元素之和,出现次数,存入
map - 定义
count,用来统计a+b+c+d = 0出现的次数 - 遍历C和D,
map中找有0-(c+d)吗?有:**count**加上出现次数
用Set存
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @param {number[]} nums3
* @param {number[]} nums4
* @return {number}
*/
var fourSumCount = function(nums1, nums2, nums3, nums4) {
// 类似与两数相加,用map存
let map = new Map() //key为a+b,value为出现次数
for (let a of nums1) {
for (let b of nums2) {
let sum = a + b //先求a+b放入map
map.set(sum, (map.get(sum) || 0) + 1) //如果之前没有0+1变为1,有就取值+1
}
}
let count = 0 // 存最终结果
for (let c of nums3) {
for (let d of nums4) {
let sub = 0 - (c+d) //求让和为0的
if(map.has(sub)) //在map中
count = count + map.get(sub) //个数+出现次数
}
}
return count
};
383. 赎金信
383. 赎金信 后一个字符串中能找到前一个字符串中的所有元素
用数组映射
/**
* @param {string} ransomNote
* @param {string} magazine
* @return {boolean}
*/
var canConstruct = function(ransomNote, magazine) {
let hash = new Array(26).fill(0) //哈希映射26个字母
let base = "a".charCodeAt()
for (let i = 0; i < ransomNote.length; i++) { //r数组有的++
hash[ransomNote[i].charCodeAt() - base]++
}
for (let j = 0; j < magazine.length; j++) { //m数组有的--
hash[magazine[j].charCodeAt() - base]--
}
for (let h of hash) { //最后如果还有>0的数,说明存在r数组中有,m数组中没有的
if (h > 0) return false
}
return true
};
15. 三数之和
15. 三数之和 在一个数组内,找三个数的和为0,形成的不能重复的数组
用双指针解题:a + b + c = 0
- 首先对数组进行排序(小->大)
- 用
i去遍历数组(a),l从i下一个(b),r从最后一个(c),向中间移动找到合适的 - 可以用
-1 -1 0 0 1 1 3判断去重 - 判断去重要找与前一个是否相等,相等说明这个数的已经处理过了,再处理也是一样的重复了
- 注意:不能先去重再找,会少一些情况:比如
[0, 0, 0]就直接被删除了
三指针剪枝
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
nums.sort((a, b) => a-b) // 按照升序对数组排序
let result = [], conut = 0 //存最后得到的数组
for (let i = 0; i < nums.length; i++) { // i去遍历数组
// 如果排序后第一个元素都>0,再与后面元素相加怎么也不可能为0
if (nums[i] > 0) break
// a去重,如果前面已经有了说明重复了
if (i > 0 && nums[i] === nums[i-1]) continue
let l = i + 1 //l从i下一个
let r = nums.length - 1 //r从最后一个
while (l < r) { //循环找让a+b+c = 0
if (nums[i] + nums[l] + nums[r] > 0) r-- //>0 r前移让和变小
else if (nums[i] + nums[l] + nums[r] < 0) l++ //<0 l后移让和变大
else{ //找到等于0
result[conut++] = [nums[i], nums[l], nums[r]] //加入结果数组
// 对l,r去重,移一位
while (nums[l + 1] === nums[l]) l++
// 如果下一个相同就跳过,找下一个不相同的
while (nums[r - 1] === nums[r]) r--
// 找到答案时,双指针同时收缩
l++ // 跳到不相同的下一个
r--
}
}
}
return result
};
18. 四数之和
18. 四数之和 三数之和的升级版
- 四数之和的双指针解法是两层for循环nums[k] + nums[i]为确定值,一样是
l``r移动找和满足target,五数之和、六数之和等等都采用这种解法 - 剪枝的时候要用
break直接结束循环(后面都不看了),不能直接return,nums[i] > target && nums[i] >=0比如:数组是[-4, -3, -2, -1],target是-10,不能因为-4 > -10而跳过,看nums[i]是否>=0,如果>=0,说明后面比它大的都是正数,加上正数只会越来越大 - 去重:与前一个相等,直接结束这次,继续下次循环
continue(这个数不用看了)
- 排序:从小到大
- 遍历前面的值
- 剪枝,排除不满足的情况:已经大于
target且>=0后面值越来越大、和前面相同:必须加上>起始值限制i > k + 1、k > 0 l, r分别从剩下的往中间遍历
四指针剪枝
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function(nums, target) {
let result = [], count = 0 // 存
nums.sort((a, b) => a - b) // 排序
for (let k = 0; k < nums.length; k++) { //k遍历数组
// 剪枝:排除不满足的情况
//一级剪枝
if (nums[k] > target && nums[k] >= 0 ) break // 不可能==target
if (k > 0 && nums[k] === nums[k - 1]) continue // k去重
for (let i = k + 1; i < nums.length; i++) { //i从k+1
let l = i + 1
let r = nums.length - 1
let sum = nums[k] + nums[i] // 已确定的k,i和
//二级剪枝
if(sum > target && sum >= 0) break
// 第一次i = K + 1时不能和前面比较剪枝i > K + 1
if (i > k + 1 && nums[i] === nums[i - 1]) continue
while (l < r) {
if (sum + nums[l] + nums[r] > target) r--
else if (sum +nums[l] + nums[r] < target) l++
else {
result[count++] = [nums[k], nums[i], nums[l], nums[r]]
while (l < r && nums[l + 1] === nums[l]) l++
while (l < r && nums[r - 1] === nums[r]) r--
l++
r--
}
}
}
}
return result
};