LeetCode 之 JavaScript 解答第十五題 —— 三數之和(3Sum)
Time:2019/4/3
Title:3Sum
Difficulty: medium
Author:小鹿
題目三:ADD Two Numbers
Given an arraynums
of n
integers, are there elements a
, b
, c
in nums
such that a
+ b
+ c
= 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4], A solution set is: [ [-1, 0, 1], [-1, -1, 2] ]
Solve:
▉ 演算法思路:
2、先對陣列內資料進行一次排序。O(nlogn) 3、最外層一個 for 迴圈,先把其中一個值固定住(存放到變數),然後分別用兩個指標指向資料的非固定值的頭部和尾部,通過 while 迴圈來遍歷。 4、如果三個資料相加等於 0 了,就儲存該三個值且更新 head 和 end 指標。 5、如果不等於小於或大於 0 ,就更新 head 和 end 指標移動重新查詢符合條件的值。 6、返回結果集 result。
▉ 邊界條件:
2、判斷固定值、head 以及 end 指標的值前後元素是否相同,去掉重複計算。 3、判斷 head 和 end 指標的大小關係。 4、注意去掉重複資料
▉ 程式碼實現:
/** * @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 內部使用的歸併排序,兩者的區別就是快速排序不如歸併排序穩定,但是大多數情況下還是可以使用快排的,只有個別要求必須穩定。所謂的穩定性就是原始資料相同的元素在排序之後位置是否改變?
效能問題:
1、sort 會產生效能問題,因為無論是快排還是歸併,都涉及到遞迴,如果遞迴深度過大,導致堆疊溢位,v8 引擎的解決辦法就是設定一個遞迴深度閾值,小於閥值採用插入排序,大於閥值改用快排。
2、快排在在最差的情況下演算法也會退化,因為根據 pivot 選擇的不同,最壞情況時間複雜度退化到 O(n^2).
3、怎麼進行改進?有興趣可以看下方參考連結!
歡迎關注我個人公眾號:「一個不甘平凡的碼農」,記錄了自己一路自學程式設計的故事。
LeetCode 其他題目解析,請關注我Github:https://github.com/luxiangqia...