解题思路:
1、淳朴解法:双层遍历,O(n^2) 的复杂度,这个复杂度非常容易导致你的算法超时,不推荐。
2、空间换时间,Map 来帮忙
大家记住一个结论:几乎所有的求和问题,都可以转化为求差问题。
- var twoSum = function(nums, target) {
- let obj = {} //创建一个对象来存储出现过的数字-对应的索引
- for (let i = 0; i < nums.length; i++) {
- const curNum = nums[i]; //当前元素
- const targetNum = target - curNum //几乎所有的求和问题,都可以转化为求差问题
- const targetNumIndex = obj[targetNum]//找到在obj中的索引
- if (targetNumIndex !== undefined) {
- return [targetNumIndex, i] //如果存在, 直接返回[目标元素的索引, 当前索引]
- } else {
- obj[curNum] = i //如果不存在,存入当前的元素和对应的索引
- }
-
- }
- };
- var twoSum = function(nums, target) {
- const map = new Map();
- for (let i = 0; i < nums.length; i++) {
- const curNum = nums[i];
- const targetNum = target - curNum;
- const targetNumIndex = map.get(targetNum);
-
- if (targetNumIndex !== undefined) {
- return [targetNumIndex, i];
- } else {
- map.set(curNum, i);
- }
- }
- };
解题思路:
外层循环遍历指针ℹ️
内层用双指针寻找满足条件的元素
先排序,可以方便去重
- var threeSum = function (nums) {
- nums.sort((a, b) => a - b) //排序
- const result = []
- for (let i = 0; i < nums.length-2; i++) { //外层遍历,内层双指针
- const n1 = nums[i];
- if (n1 > 0) break // n1比0大,就不用做了
- if (i - 1 >= 0 && nums[i - 1] == n1) continue //重复的数也跳过
-
- let left = i + 1 //左指针
- let right = nums.length - 1 //右指针
- while (left < right) {
- let n2 = nums[left],n3 = nums[right];
- if (n1 + n2 + n3 === 0) {
- result.push([n1, n2, n3])
- while (left < right && nums[left] === n2) left++ // 去重,直到指向不一样的数
- while (left < right && nums[right] === n3) right-- //去重, 直到指向不一样的数
- } else if (n1 + n2 + n3 < 0) { //小于0,那么左指针往右移
- left++
- } else { //大于0,那么右指针左移
- right--
- }
- }
-
- }
- return result
- };
解题思路:排序+双指针
参考三数之和,相比多了一层循环
注意事项:
!!!!:一定注意代码中是 先进行了指针的移动 还是 先进行了去重的比较, 对于不同的顺序, 比较的元素是完全不同的。
若先进行了指针的移动, 对于左指针来说, 需要比较的元素就是 当前元素和前面的一个元素
对于 i 和 j 由于每次循环完都先 i++、j++ 了,所以是 先进行了指针的移动再判断重复,所以是 nums[i] === nums[i - 1]
若先进行去重的比较, 那比较的元素就是 当前元素和后面的一个元素, 再进行指针的移动. 对于右指针的情况正好是完全相反的.while (left < right && nums[left + 1] === nums[left]) left++ // 去重
while (left < right && nums[right - 1] === nums[right]) right-- // 去重
对于 left 和 right ,是 先进行了判断重复再进行指针的移动,所以是两个 while 循环后才 left++, right--
- var fourSum = function (nums, target) {
- const len = nums.length
- if (len < 4) return []
- nums.sort((a, b) => a - b) //排序
- const result = []
- for (let i = 0; i < len - 3; i++) {
- if (i > 0 && 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) {
- result.push([nums[i], nums[j], nums[left], nums[right]])
- while (left < right && nums[left + 1] === nums[left]) left++ // 去重
- while (left < right && nums[right - 1] === nums[right]) right-- // 去重
- // 找到一个符合条件的了,然后两指针同时收缩
- right--
- left++
- } else if (nums[i] + nums[j] + nums[left] + nums[right] > target) {
- right--
- } else {
- left++
- }
- }
-
- }
- }
- return result
- };