LeetCode算法學習之--數組--三數之和

你們好今天給你們分享下一道 LeetCode 中等難度 的題目 三數之和javascript

這裏主要是分享思路和註釋,供你們更好的理解題目解法,代碼部分是參考LeetCode 轉寫成javascript 代碼,前端

題目

給你一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出全部和爲 0 且不重複的三元組。java

注意:答案中不能夠包含重複的三元組。算法

示例 1:

輸入:nums = [-1,0,1,2,-1,-4]
輸出:[[-1,-1,2],[-1,0,1]]
示例 2:

輸入:nums = []
輸出:[]
示例 3:

輸入:nums = [0]
輸出:[]


複製代碼

分析

1.爲了去重須要排序+使用Set數組

2.由於暴力法是3層迭代,時間複雜度是O(n^3),因此想辦法找到k同時減低複雜度是關鍵markdown

一種有三種解法網絡

1.暴力法 O(n^3)oop

2.Set值的方式減小時間複雜度,由於set查詢爲O(1)學習

3.雙指針內夾 O(n^2)ui

解法一:暴力法(經過不了,只提供思路)

思路
1.三層遍歷數組 判斷每一種可能性
2.添加set 來防止重複
3.必定要排序,否則會統計到重複的數據
*/
var threeSum = function (nums) {
  const set = new Set();
  const res = [];
  // 必定要排序 否則組合很差統計 例如 [[-1,0,1],[-1,2,-1],[0,1,-1]]
  nums.sort((a, b) => a - b);
  // 第一層能夠是 nums.length - 2, 由於給 j 和k 留2個位置,同理以下
  for (let i = 0; i < nums.length - 2; i++) {
    // 第二層的起點是 j=i+1,由於是題目不能同一個位置上的同一個元素不能選擇2次,同理以下
    for (let j = i + 1; j < nums.length - 1; j++) {
      for (let k = j + 1; k < nums.length; k++) {
        const key = nums[i] + "_" + nums[j] + "_" + nums[k];
        if (nums[i] + nums[k] + nums[j] === 0 && !set.has(key)) {
          res.push([nums[i], nums[k], nums[j]]);
          set.add(key);
        }
      }
    }
  }

  return res;
};

/* 複雜度 時間 O(n^3) 空間 O(1) */
複製代碼

解法二:Set 法

代碼借鑑 leetcode-cn.com/problems/3s…

1.排序 避免重複,
2.由於不能有重複的三元組,因此利用Set 來去重
3.採用遍歷的方式, 看下是否能獲取 三個元素相加爲0 的狀況
4.暴力法不一樣的地方在於, 再也不採用第三層遍歷,而是使用Set的方法來判斷是否存在 v= -nums[i] - nums[j],
由於set的查詢時間複雜度爲O(1) 因此總的複雜度爲O(n^2)
*/

var threeSum = function (nums) {
  const res = [];
  // 去重使用
  const uniqueSet = new Set();
  nums.sort((a, b) => a - b);

  for (let i = 0; i < nums.length - 1; i++) {
    // 存放 nums[j]的值
    const set = new Set();
    for (let j = i + 1; j < nums.length; j++) {
      // 須要求得的值
      const v = -nums[i] - nums[j];
      // 三元數組的惟一標識,放入set中防止重複取值
      const str = nums[i] + "_" + v + "_" + nums[j];
      if (set.has(v) && !uniqueSet.has(str)) {
        res.push([nums[i], v, nums[j]]);
        uniqueSet.add(str);
      } else {
        set.add(nums[j]);
      }
    }
  }
  return res;
};

/* 複雜都 時間 O(n^2) 空間 O(n) */
複製代碼

2.png

解法二:雙指針

代碼借鑑 leetcode-cn.com/problems/3s…

思路
1.排序防止重複
2.遍歷一次元素,獲取一個三個元素中的一個,nums[i],
3.再次遍歷一次數組,利用雙指針 左邊放置一個指針j 右邊放置一個指針k,往中間內夾
令 sum = nums[i]+nums[j]+nums[k],由於數組有序
若是sum>0 則左邊k對應的值大了 因此應該k--,若是sum<0 ,j--
*/

var threeSum = function (nums) {
  const res = [];
  // 老規矩 排序防止重複的狀況發生
  nums.sort((a, b) => a - b);
  // 遍歷
  for (let i = 0; i < nums.length; i++) {
    // 若是nums[i]都已經大於0了, 那麼其餘元素相加不可能再等於零 因此直接break
    if (nums[i] > 0) break;
    // 說明有重複, 可是不能判斷 nums[i]===nums[i+1]的時候就continue 由於會錯過元素例如(-1,-1,2) 這種狀況就會被錯過
    if (i > 0 && nums[i - 1] === nums[i]) continue;

    for (let j = i + 1, k = nums.length - 1; j < k; ) {
      const sum = nums[i] + nums[j] + nums[k];
      // 說明nums[k]大了, 因此須要k--
      if (sum > 0) {
        k--;
        // 說明nums[j]小了, 因此須要j++
      } else if (sum < 0) {
        j++;
      } else {
        // 說明找到了答案了
        res.push([nums[i], nums[j], nums[k]]);
        while (j < k && nums[j] === nums[j + 1]) j++;
        while (j < k && nums[k] === nums[k - 1]) k--;
        j++;
        k--;
      }
    }
  }

  return res;
};
/* 複雜度 時間 O(n^2) 空間 O(1) */
複製代碼

3.png

總結

這道題 ,考察你們對雙指針 和 Set的理解,由於他們能夠很好的下降時間複雜度

你們能夠看看我分享的一個專欄(前端搞算法)裏面有更多關於算法的題目的分享,但願可以幫到你們,我會盡可能保持天天晚上更新,若是喜歡的麻煩幫我點個贊,十分感謝

文章內容目的在於學習討論與分享學習算法過程當中的心得體會,文中部分素材來源網絡,若有侵權,請聯繫刪除,郵箱 182450609@qq.com

今天頗有幸的去支持了下鴻星爾克和蜜雪冰城,不得不說爲中國的良心企業點贊,爲個人祖國感到驕傲,鄭州加油!河南加油!中國加油!

相關文章
相關標籤/搜索