关于求X个数之和问题的解法

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在x个元素,使得 x1 + x2 + ... 的值与 target 相等?找出全部知足条件且不重复的元组。数组

首先

咱们先将这个问题简化,变成下面这个亚子优化

  • x=1 -> 遍历 nums 找到知足要求的值,而后push进数组,注意去重
    let result = []
    let hash = {} //使用hash来对结果进行去重
    for(let i = 0, len = nums.length; i < len; i++){
        if(nums[i] === target && hash[nums[i]] === undefined) {
             result.push(nums[i])
             hash[nums[i]] = true
        }
    }
    return result
    复制代码
  • x=2 -> 遍历两次 nums 找到知足要求的值的组合,而后push进数组,注意去重
    let result = []
    let hash = {} //使用hash来对结果进行去重for(let i = 0, len = nums.length; i < len; i++){
        for(let j = 0; j < len; j++){
            if(nums[i] + nums[j] === target
              && hash[[nums[i], nums[j]]] === undefined
              && hash[[nums[j], nums[i]]] === undefined){
                hash[[nums[i], nums[j]]] = true
                result.push([nums[i], nums[j]])
            }
        }
    }
    return result
    复制代码
    还可使用键值对象来减小一次循环
    let map = {}
    for(let i = 0, len = nums.length; i < len; i++){
        if(map[target - nums[i]] !== undefined){
            result.push([nums[i], nums[map[target - nums[i]]]])
        } else{
            map[nums[i]] = i
        }
    }
    return result
    复制代码
  • x=3 -> ······
    for(){
        for(){
            for(){
                ···
            }
        }
    }
    return result
    复制代码
  • ······

这样看能够解决问题,可是好像不太聪明的亚子。并且若是求全部知足要求的组合,不限制组合中数字的个数就不能用这种层层for循环的解法。spa

进阶

  • 排序+指针指针

    这种方法适用于2、3、四层循环的优化,具体思路为:先选取一个数组中的数字,而后初始化指针来对其余数字进行遍历,找到知足的条件。code

    • 咱们以x=3为🌰
    var threeSum = function(nums, target) {
      let result = [],
          len = nums.length
      if(len < 3){
          return result // 边界处理
      }
      nums.sort((a, b) => a - b) // 排序
      // 把L和R都设置在i的后边而且遇到值相等的就把下标日后移动
      // 能够保证每次找到的知足要求的组合都是惟一的
      for(let i = 0; i < len ; i++){
          if(nums[i] === nums[i-1]) continue // 去重
          let L = i + 1
          let R = len - 1
          while(L < R){
              let sum = nums[i] + nums[L] + nums[R]
              if(sum === 0){
                  result.push([nums[i],nums[L],nums[R]])
                  while (L<R && nums[L] === nums[L+1]) L++ // 去重
                  while (L<R && nums[R] === nums[R-1]) R-- // 去重
                  L++
                  R--
              }
              else if (sum < 0) L++
              else if (sum > 0) R--
          }
      }        
      return result
     }
    复制代码
  • 回溯对象

    若是题目要求求出全部知足要求的元组而不限制长度,咱们能够采用回溯法来解决,具体思路为:原来数组中每一个数字都有两种选择那就是当个好人或者作个卧底,,那就是被选中和不被选中,以此咱们能够来构建二叉树并进行遍历找到知足要求的元组。排序

    • 递归实现以下:
      var sum = function(nums, target) {
          let tempNums = nums.slice(),
              result = [],
              buffer = [],
              index = 0,
              hash = {}
          let _sum = (index, target) => {
              if(target === 0 && buffer.length !== 0){
                  result.push(buffer.slice())
              }
              if(index === tempNums.length){
                  return
              }
              buffer.push(tempNums[index]) // 选中
              _sum(index+1, target - tempNums[index])
              buffer.pop() // 不选
              _sum(index+1, target)
          }
          _sum(index, target)
          // 去重返回
          return result.filter(_ => {
              _.sort((a, b) => a-b)
              if(hash[_] === undefined){
                  hash[_] = true
                  return _
              }
          })
      }
      复制代码

最后

关于求x个数之和的问题就聊到这里,若有错误,恳请指正👀递归

相关文章
相关标签/搜索