1.四数相加 II leetcode454
此题类似于昨天的力扣第一题,两数相加题。在map中先存入第一个数组,在遍历第二个数组,在map里面找 有没有减去第一个值的值存在,如果存在,即为找到了
此题是四数相加,所以可以先将两个数组相加,在将另外两个相加,最终实现四数相加
var fourSumCount = function (nums1, nums2, nums3, nums4) {
// 四个数组,把它分为两个数组+两个数组
// 将两个数组元素之和,和出现的次数,放到map中,key值为nums1[i]+nums2[j],value为次数
let map = new Map();
let count = 0;
for (let i = 0; i < nums1.length; i++) {
for (let j = 0; j < nums2.length; j++) {
map.set(nums1[i] + nums2[j], (map.get(nums1[i] + nums2[j]) || 0) + 1)
}
}
// 在map中寻找,用0减去第三个数组和第四个数组的和,如果找到,就将该次数累加起来,
for (let m = 0; m < nums3.length; m++) {
for (let n = 0; n < nums4.length; n++) {
if (map.get(0 - (nums3[m] + nums4[n]))) {
// 注意,累加次数。而不是每次加一
count += map.get(0 - (nums3[m] + nums4[n]))
}
}
}
return count
}
2.赎金信 leetcode383
使用数组计数
var canConstruct = function (ransomNote, magazine) {
let arr = new Array(26).fill(0);
let base = 'a'.charCodeAt();
for (let i = 0; i < magazine.length; i++) {
arr[magazine[i].charCodeAt() - base]++
}
for (let j = 0; j < ransomNote.length; j++) {
if (!arr[ransomNote[j].charCodeAt() - base]) {
return false
}
// 注意:在arr中的一定要减
arr[ransomNote[j].charCodeAt() - base]--
}
return true
}
3.三数之和 leetcode15
给定一个数组,返回所有和为 0
且不重复的三元组
这里说下双指针解法,这里还有一个地方需要注意的是:如何去重
首先是求三元数组之和,及a+b+c=0;首先确定三个数分别为什么
i,left,right分别为a,b,c三个数字,i是遍历的指针,left是i的下一位,right是数组的最后一个元素。
因为数组排序过,所以如果相加大于0,就将right向前移动,如果小于0,就将left向右移动
接下来是去重
a的去重,即nums[i]的去重。
如果使用nums[i]===nums[i+1], i+1指向的是left,这就变成了所组成的三元数组里不能有重复的元素
但是题目要求的是不重复的三元数组
所以使用nums[i]===nums[i-1],这样a就不会重复加入数组中
b和c的去重
当我们得到了想要的组合后,要进行bc去重
while(left<right&&nums[left]===nums[left+1]{
left++
}
while(left<right&&nums[right]=nums[right-1]{
right--
}
最终代码
var threeSum = function (nums) {
const res = []
// 先排序
nums.sort((a, b) => a - b);
for (let i = 0; i < nums.length; i++) {
// 排序过,如果第一个数就大于0,就无法使其等于0
if (nums[i] > 0) {
return res
}
let left = i + 1;
let right = nums.length - 1;
// a去重
if (nums[i] === nums[i - 1]) {
continue
}
while (left < right) {
let thresSum = nums[i] + nums[right] + nums[left]
if (thresSum > 0) {
right--
} else if (thresSum < 0) {
left++
} else {
res.push(nums[i], nums[left], nums[right]);
// bc去重
while (left < right && nums[left] === nums[left + 1]) {
left++
}
while (left < right && nums[right] === nums[right - 1]) {
right++
}
left++;
right--;
}
}
}
return res
};
4.四数之和 leetcode18
跟三数之和类似,多了一层循环,但是圈复杂度有点高,可以进行函数提取降低复杂度
var fourSum = function (nums) {
//接收结果
let res = []
//排序
nums.sort((a, b) => a - b)
for (let k = 0; k < nums.length - 3; k++) {
// 跟三数之和相比,这里不能k>target就去掉,
// 因为target可能是任意值,有可能是负值,如果nums[k]是负数,负数跟后面数相加,还是可能等于target
// 如[-5,-1,-1,-1],target=-8 -5>-8
if (nums[k] > target && (nums[k] >= 0 || target >= 0)) {
break
}
// 对于a去重
if (nums[k] === nums[k - 1] && k > 0) {
continue
}
// 循环第二个数
for (let i = k + 1; i < nums.length - 2; i++) {
// nums[i] + nums[k]为一个整体
if (nums[i] + nums[k] > target && (nums[i] + nums[k] >= 0 || target >= 0)) {
break
}
// i必须大于k+1
if (nums[i] === nums[i - 1] && i > k + 1) {
continue
}
let left = i + 1;
let right = nums.length - 1;
while (left < right) {
const sum = nums[k] + nums[i] + nums[left] + nums[right]
if (sum > target) {
right--
} else if (sum < target) {
left++
} else {
res.push([nums[k], nums[i], nums[left], nums[right]])
// 对left和right进行去重
while (left < right && nums[left] === nums[left + 1]) {
left++
}
while (left < right && nums[right] === nums[right - 1]) {
right--
}
// 移动指针
left++;
right--;
}
}
}
}
return res
}