2021-09-16-满足整数之和为target的题型总结

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
/**
 * @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;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值