LeetCode 之 JavaScript 解答第十五題 —— 三數之和(3Sum)

Time:2019/4/3
Title:3Sum
Difficulty: medium
Author:小鹿

題目三:ADD Two Numbers

Given an array nums of n integers, are there elements abc in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. javascript

Note:
The solution set must not contain duplicate triplets.java

Example:git

Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

Solve:github

▉ 算法思路:
一、直接用三個 for 循環遍歷全部數據,找出符合條件的數據,時間複雜度爲 O(n^3)。能不能更快效率?

二、先對數組內數據進行一次排序。O(nlogn)算法

三、最外層一個 for 循環,先把其中一個值固定住(存放到變量),而後分別用兩個指針指向數據的非固定值的頭部和尾部,經過 while 循環來遍歷。編程

四、若是三個數據相加等於 0 了,就存儲該三個值且更新 head 和 end 指針。數組

五、若是不等於小於或大於 0 ,就更新 head 和 end 指針移動從新查找符合條件的值。瀏覽器

六、返回結果集 result。函數

▉ 邊界條件:
一、判斷數組內元素是否都爲整數或負數,直接返回。

二、判斷固定值、head 以及 end 指針的值先後元素是否相同,去掉重複計算。性能

三、判斷 head 和 end 指針的大小關係。

四、注意去掉重複數據

▉ 代碼實現:
/**
  * @param {number[]} nums
  * @return {number[][]}
  */

var threeSum = function(nums) {
    //用來存取最後結果集
    let result = new Array();
    //頭指針
    let head;
    //尾指針
    let end;
    //固定值
    let fixedVal;

    //排序
    nums.sort((a, b) => {
        return a-b;
    });
    
    //判斷數組內元素是否都爲整數或負數,直接返回
    if(nums[0] > 0 || nums[nums.length - 1] < 0) return result;
    
    // 開始遍歷
    for (let i = 0; i < nums.length; i++) {
        //固定值
        fixedVal = nums[i];
        // 若是先後元素相同,跳過這次循環(固定值)
        if(fixedVal === nums[i-1]) continue;
        //一開始的固定值爲nums[0],因此頭指針爲 i+1 下一個元素
        head = i+1;
        //尾指針
        end = nums.length - 1;
        //若是頭指針小於尾指針元素
        while(head < end){
            //判斷固定值+頭指針+尾指針是否等於0
            if(nums[head] + nums[end] + fixedVal === 0){
                //聲明數組,存放這三個值
                let group =  new Array();
                group.push(nums[head]);
                group.push(nums[end]);
                group.push(fixedVal);
                result.push(group);
                //存放完畢以後,不要忘記頭指針和尾指針的移動(不然會產生死循環)
                head += 1;
                end -= 1;
                //若是頭指針知足小於尾指針且移動後的指針和移動前的指針元素相等,再往前移動
                while(head < end && nums[head] === nums[head - 1]){
                    head += 1;
                }
                 //若是頭指針知足小於尾指針且移動後的指針和移動前的指針元素相等,再日後移動
                while(head < end && nums[end] === nums[end + 1]){
                    end -= 1;
                }
             //小於 0 須要移動頭指針,由於嘗試着讓數據比原有數據大一點
            }else if(nums[head] + nums[end] + fixedVal < 0){
                head++;
            }else{
                //不然,尾指針向前移動,讓數據小於元數據
                end--;
            }
        } 
    }
    return result;
}
//測試
let nums = [-1, 0, 1, 2, -1, -4];
threeSum(nums);
▉ sort 排序:

定義:sort() 方法用於對數組的元素進行排序。 在原來數組上進行排序,不生成副本。

使用:

1)無參:按照字母的順序對元素排序,即使是數字,先轉換 String 再排序(按照字符編碼),每每得不到咱們要的結果。

2)有參:參數爲比較函數,比較函數有兩個參數 a,b (默認的 a 是小於 b 的)

  • 若 a 小於 b,在排序後的數組中 a 應該出如今 b 以前,則返回一個小於 0 的值。(從小到大)
  • 若 a 等於 b,則返回 0。(按照無參排序)
  • 若 a 大於 b,則返回一個大於 0 的值。(從大到小)

內部實現:

在 Chrome 瀏覽器中 sort 的你內部實現是快速排序,可是 FireFox 內部使用的歸併排序,二者的區別就是快速排序不如歸併排序穩定,可是大多數狀況下仍是可使用快排的,只有個別要求必須穩定。所謂的穩定性就是原始數據相同的元素在排序以後位置是否改變?

性能問題:

一、sort 會產生性能問題,由於不管是快排仍是歸併,都涉及到遞歸,若是遞歸深度過大,致使堆棧溢出,v8 引擎的解決辦法就是設置一個遞歸深度閾值,小於閥值採用插入排序,大於閥值改用快排。

二、快排在在最差的狀況下算法也會退化,由於根據 pivot 選擇的不一樣,最壞狀況時間複雜度退化到 O(n^2).

三、怎麼進行改進?有興趣能夠看下方參考連接!

參考連接:https://efe.baidu.com/blog/ta...

歡迎一塊兒加入到 LeetCode 開源 Github 倉庫,能夠向 me 提交您其餘語言的代碼。在倉庫上堅持和小夥伴們一塊兒打卡,共同完善咱們的開源小倉庫!
Github:https://github.com/luxiangqia...

歡迎關注我我的公衆號:「一個不甘平凡的碼農」,記錄了本身一路自學編程的故事。
相關文章
相關標籤/搜索