1. 两数之和 I - 无序数组
- 给定一个整数数组
nums
和 目标值target
,请你在数组中找出两个整数之和为target
对应的数组下标- 假设每种输入都只会有一个答案
nums = [ 1,1,1,1,4,5 ] ,target = 6 这种情况是不可能存在的
- 数组中同一个元素不能再答案中重复出现
- 一次for循环 + hashTable来完成
时间复杂度O(n),空间复杂度O(1)
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
// 在for循环中借用哈希表判断
let hashTable = new Map();
for (let i = 0; i < nums.length; i ++) {
// 因为get到的元素有可能为0嘛,因此需要通过undefined来判断
if (hashTable.get(target - nums[i]) != undefined) {
return [i,hashTable.get(target - nums[i])];
}
hashTable.set(nums[i],i);
}
return [];
};
167. 两数之和 II - 有序数组
- 给定的数组是 非递减顺序排列 的整数数组
- 每个输入只对应唯一答案
- 不可以使用重复使用同一个元素
- 双指针
时间复杂度O(n)
,空间复杂度O(1)
/** * @param {number[]} numbers * @param {number} target * @return {number[]} */ var twoSum = function(numbers, target) { let left = 0; let right = numbers.length - 1; while (left < right) { let sum = numbers[left] + numbers[right]; if (sum === target) { return [left + 1,right + 1]; } else { sum > target ? right -- : left ++; } } return []; };
653. 两数之和 IV - BST存储
- leetcode链接
遍历Tree
的同时用hashTable 或 set
存储,但这样没有利用上BST的特性
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @param {number} k
* @return {boolean}
*/
var findTarget = function(root, k) {
// 1. bfs + map
let map = new Map();
let queue = [root];
while (queue.length > 0) {
let p = queue.pop();
if (map.get(k - p.val) != undefined) {
return true;
}
map.set(p.val,true);
p.left && queue.push(p.left);
p.right && queue.push(p.right);
}
return false;
// 2. dfs + map
function tree_dfs(node) {
if (map.get(k - node.val) != undefined) {
return true;
}
map.set(node.val,true);
let re_val = false;
if (!re_val && node.left) {
re_val = tree_dfs(node.left);
}
if (!re_val && node.right) {
re_val = tree_dfs(node.right);
}
return re_val;
}
return tree_dfs(root);
}
中序遍历
的同时用数组存储元素,此时利用了BST的特性,所有的左子树节点小于等于父节点,所有的右子树节点大于等于父节点,从而得到一个非递减的有序数组
let list = [];
function inorder(node) {
if (node) {
inorder(node.left);
list.push(node.val);
inorder(node.right);
}
}
inorder(root);
let left = 0;
let right = list.length - 1;
while (left < right) {
let sum = list[left] + list[right];
if (sum == k) {
return true;
} else {
sum > k ? right -- : left ++;
}
}
return false;
- 可以引申出非递归如何实现
中序遍历
,前序遍历,后序遍历 - 如何根据
中序遍历
+前序遍历
或后序遍历
得到一颗二叉树
007. 数组中和为 0 的三个数
- 贴上代码,详细分析看18. 四数之和
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
// 三重for循环
if (nums.length < 3) return [];
// 排序后,for + 双指针找排序数组两数之和
// O(logn)
nums.sort((a,b) => a - b);
let length = nums.length;
let res = [];
// O(n^2)
for (let i = 0; i < length; i ++) {
if (nums[i] > 0) continue;
if (i > 0 && nums[i] == nums[i - 1]) continue;
let one = i + 1;
let two = length - 1;
let target = -nums[i];
while (one < two) {
let sum = nums[one] + nums[two];
if (sum === target) {
res.push([nums[i],nums[one],nums[two]]);
// 内层双指针可能有多个符合,但要去重,该数组是排序的
while (one < two && nums[one] === nums[++one]);
while (one < two && nums[two] === nums[--two]);
} else {
sum > target ? two -- : one ++;
}
}
}
return res;
};
18. 四数之和
- leetcode链接
- 思维类似三数之和,两层for循环处理两个数 + 双指针处理两个数
- for循环去重时,
第一次不用去
if (i > 0 && nums[i] === nums[i - 1]) continue;
…
if (j > i + 1 && nums[j] === nums[j - 1]) continue;- 边界条件需要处理
- 数组空或元素少于4个
- 排完序的数组前四个元素之和都大于target,或前面加上后面都小于target
- for循环去重时,
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function(nums, target) {
let length = nums.length;
if (length < 4) return [];
let res = [];
// 排序:O(nlogn)
nums.sort((a,b) => a - b);
// 两层for循环 + 双指针:O(n^3)
for (let i = 0; i < length - 3; i ++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
// 特殊情况优化
if (nums[i] + nums[i + 1] + nums[ i + 2] + nums[ i + 3] > target) break;
if (nums[i] + nums[length - 1] + nums[length - 2] + nums[length - 3] < target) continue;
for (let j = i + 1; j < length - 2; j ++) {
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
// 特殊情况优化
if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;
if (nums[i] + nums[j] + nums[length - 1] + nums[length - 2] < target) continue;
let left = j + 1;
let right = length - 1;
let two_target = target - nums[i] - nums[j];
while (left < right) {
let sum = nums[left] + nums[right];
if (sum === two_target) {
res.push([nums[i],nums[j],nums[left],nums[right]]);
while (left < right && nums[left] == nums[++left]);
while (left < right && nums[right] == nums[--right]);
} else {
sum > two_target ? right -- : left ++;
}
}
}
}
return res;
};