LeetCode No15. 三數之和
阿新 • • 發佈:2022-04-20
題目
給你一個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有和為 0 且不重複的三元組。
注意:答案中不可以包含重複的三元組。
示例 1:
輸入:nums = [-1,0,1,2,-1,-4]
輸出:[[-1,-1,2],[-1,0,1]]
示例 2:
輸入:nums = []
輸出:[]
示例 3:
輸入:nums = [0]
輸出:[]
思路
首先第一反應就是暴力,三重迴圈,然後時間複雜度O(n^3),按照題目給的資料範圍應該不會超時,然而寫完之後提交直接超時。那就優化唄,看題目的樣例,似乎是對返回的順序什麼的沒有要求,那麼就想到排序,然後對排序後的陣列去取值,這樣就想到如下兩種方法:
二分查詢
既然三重迴圈不行,那我減少一層迴圈試試,先用兩層迴圈找到兩個數a、b,因為需要三個數之和為0,那麼另外一個數必然是 -(a+b),因為陣列已經有序,找這個數就可以用二分,時間複雜度為O(n^2*log(n))。
雙指標
既然已經能減少一層迴圈,那麼是否還能再減少一層迴圈呢?顯然是可以的,用一層迴圈遍歷出第一個數a,對於剩下的兩個數,由於陣列已經排好序了,只需要用兩個指標去從陣列的頭和尾取數,只要找到的兩個數和a相加等0即可。
AC程式碼
二分查詢
點選檢視程式碼
class Solution { private int b_search(int[] nums, int low, int high, int num) { while( low <= high ) { int mid = ( low + high ) / 2; if( nums[mid] == num ) { return mid; } else if( nums[mid] > num ){ high = mid - 1; } else { low = mid + 1; } } return -1; } public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> res = new ArrayList<>(); int len = nums.length; if( len < 3 ){ return res; } Arrays.sort(nums); for(int i=0; i<len; i++) { if( i!=0 && nums[i-1]==nums[i] ) { continue; } int last = i+1; while( last < len-1 ) { if( last > i+1 && nums[last-1]==nums[last] ) { last ++; continue; } int num = nums[i] + nums[last]; if( num > 0 ) { break; } int ind = b_search(nums, last+1, len-1, num*-1); if( ind!=-1 ) { List<Integer> list = new ArrayList<>(); list.add(nums[i]); list.add(nums[last]); list.add(nums[ind]); res.add(list); } last ++; } } return res; } }
雙指標
點選檢視程式碼
class Solution { public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> res = new ArrayList<>(); int lasta = -100005; int n = nums.length; Arrays.sort(nums); for(int i=0; i<n; i++) { int a = nums[i]; if( lasta==a ) { continue; } lasta = a; int low = i+1; int high = n - 1; while( low < high ) { int sum = a + nums[low] + nums[high]; if( sum>0 ) { high --; } else if( sum < 0 ) { low ++; } else { List<Integer> list = new ArrayList<>(); list.add(a); list.add(nums[low]); list.add(nums[high]); res.add(list); while(low<high && nums[low]==nums[low+1]) { low ++; } while(low<high && nums[high]==nums[high-1]) { high --; } low ++; high --; } } } return res; } }