一、454. 四数相加 Ⅱ
从今天开始我们就得尝试一些更为困难的题目了哈,首先看一下454题的题目介绍:
刚看到这题的时候其实我脑袋里是懵的,后来经过仔细地思考,我认为使用Map去设计是一个不错的想法。
首先,我们先声明一个map,key为nums1与nums2每个数之和,而value则为该和出现的次数。之后我们再遍历nums3和nums4,对于这两个数组,我们应求出 0 - (nums3[k] + nums4[l])在map中的value值,并把它加到我们最终的count上,也就是我们的返回值。
具体代码如下:
/**
* @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(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);
}
}
for(let i = 0;i < nums3.length;i++){
for(let j = 0;j < nums4.length;j++){
count += (map.get(0 - (nums3[i] + nums4[j])) || 0);
}
}
return count;
};
二、383. 赎金信
这题整体的思路和 242. 有效的字母异位词很像,本题我们应该采用数组,最后只要最后数组不存在大于0的值就返回true,否则位false。
具体代码如下:
/**
* @param {string} ransomNote
* @param {string} magazine
* @return {boolean}
*/
var canConstruct = function(ransomNote, magazine) {
let arr = new Array(26).fill(0);
const a_code = "a".charCodeAt();
for(const a of ransomNote){
arr[a.charCodeAt() - a_code]++;
}
for(const b of magazine){
arr[b.charCodeAt() - a_code]--
}
for(const num of arr){
if(num > 0){
return false;
}
}
return true;
};
三、15.三数之和
我们先来看一下题目背景:
某种程度上讲,三数之和是一道非常具有挑战性的题目。为了解决这一问题,我们采用三指针法进行解题。
首先我们的一步就是排序,排序的时候用的是sort()函数,并在函数里面调用函数compare()。排完序后,nums为从左到右的非递减数列。
这时候我们声明三个指针,第一个指针为i,一开始指向index为0的位置,作用是在for循环中不断遍历。第二个指针为left,指向i + 1的位置。第三个指针为right,指向数组最右侧的数。当三个指针指向的数大于0时候,right指针向左移一格;同理,小于0时往右移一格;等于的时候,返回数组的指针给res,并将left值加1,right值-1.
但做到这一步是远远不够的,因为我们忘记了去重的事宜。首先,在一开始我们要对nums[i]判定,如果其大于0,那就没必要运行后面的代码了。此外,在i>=1的情况,如果其值与nums[i-1]值相同,那么相当于这一类情形我们已经考虑过了,直接continue完事。最后,在三数之和判定为0后,我们要继续判定nums[left+1]和nums[left],nums[right-1]和nums[right]。判定完成后可以方便我们去重。
具体代码如下:
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
const res = [];
nums.sort((a,b) => a - b);
for(let i = 0;i < nums.length;i++){
if(nums[i] > 0) return res;
if(i >= 1 && nums[i] === nums[i - 1]) continue;
let left = i + 1;
let right = nums.length - 1;
while(left < right){
if(nums[i] + nums[left] + nums[right] < 0){
left++;
}
else if(nums[i] + nums[left] + nums[right] > 0){
right--;
}
else{
res.push([nums[i],nums[left],nums[right]]);
while(left < right && nums[left] === nums[left + 1]){
left++;
}
while(left < right && nums[right] === nums[right - 1]){
right--;
}
left++;
right--;
}
}
}
return res;
};
四、18.四数之和
这题的大致思路是和三数之和相似的,主要的区别就是得多加一层循环了。其它方面区别倒没有那么大哈。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function(nums, target) {
const res = [];
const len = nums.length;
nums.sort((a,b) => a-b);
if(len < 4) return res;
for(let i = 0;i < len - 3;i++){
if(i >= 1 && nums[i] === nums[i - 1]) continue;
for(let j = i + 1;j < len - 2;j++){
if(j > i + 1 && nums[j] === nums[j - 1]) continue;
let left = j + 1;
let right = len - 1;
while(left < right){
if(nums[i] + nums[j] + nums[left] + nums[right] > target){
right--;
}
else if(nums[i] + nums[j] + nums[left] + nums[right] < target){
left++;
}
else{
res.push([nums[i],nums[j],nums[left],nums[right]]);
while(left < right && nums[left] === nums[left + 1]){
left++;
}
while(left < right && nums[right] === nums[right - 1]){
right--;
}
left++;
right--;
}
}
}
}
return res;
};