關於求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個數之和的問題就聊到這裏,若有錯誤,懇請指正👀遞歸

相關文章
相關標籤/搜索