最強面試手冊:圖解

問題15:三數之和(3 Sum)

給定一個包含n個整數的數組nums,判斷nums中是否存在三個元素a,b,c,使得a+b+c=0,並找出全部知足條件且不重複的三元組。(注:不包含重複的三元組)。面試

例如,給定數組nums=[-1,0,1,2,-1,-4],則知足要求的三元組集合爲:
[ [-1, 0, 1], [-1, -1, 2] ]算法

思路分析:

首先對數組進行排序,用於定位基準點。假設以排序後首個固定元素nums[i](i=0)爲起始點,再以左指針指向nums[i+1](簡略記爲nums[l]),右指針指向nums[len-1](簡略記爲nums[r]),即指向nums[i]右側元素的兩端,計算三數之和是否知足條件爲0。如不知足且和小於0,則L++;反之則R--,有序移動兩端指針,當L與R碰撞時(L>=R)時本輪遍歷結束,右移起始點(i++);如三數之和爲0,知足條件則記錄並繼續移動兩端指針。
最強面試手冊:圖解
圖1:引用自知乎的圖解數組

因爲按小到大排序,所以若是做爲起始點的nums[i]>0,則三數之和必然沒法等於0,此時可結束循環。若是nums[i]==nums[i−1],則說明該元素重複,根據題意須要跳過,避免輸出重複的結果。ide

此外,當三數之和爲0時,假設nums[L]==nums[L+1]會致使結果重複,須要跳過該元素(L++);若是nums[R]==nums[R−1]一樣會致使結果重複,也須要跳過該元素(R--)。整體來講,時間複雜度爲:O(n2)。測試

代碼實現:

public static void sum3(int[] nums) {
  if(nums != null && nums.length > 2) {
   // 初始化並對數組排序
   Arrays.sort(nums);  
   //定位起始點元素右側的兩端指針
   int l = 0, r = 0;
   for (int i = 0; i < nums.length; i++) {
     // 若是起始點元素大於0,因爲已排序,
     // 其與右側兩端元素之和必然大於0
      if (nums[i] > 0) break;
     // 若是起始點右移,當前元素與以前相同
     // 則須要跳過避免出現重複結果
     if (i > 0 && nums[i] == nums[i - 1]) continue;
     // 定義起始點元素右側的兩端指針
     // 分別指向其右側元素數組的左右兩端
     l = i + 1;
     r = nums.length - 1;

     while (l < r)
       if (nums[i] + nums[l] + nums[r] == 0) {
         // 當三數之和爲0,則標記,並有序移動兩端指針
         // 與此同時跳太重複元素
         while (l < r && nums[l] == nums[l + 1]) l++;
         while (l < r && nums[r] == nums[r - 1]) r--;
         l++;
         r--;
       }
         // 如三數之和小於0,則左指針右移,增大三數之和
       else if (nums[i] + nums[l] + nums[r] < 0) l++;
         //如三數之和大於於0,則右指針左移,減少三數之和
       else if (nums[i] + nums[l] + nums[r] > 0) r--;
   }
  }
}

以上僅爲參考,解題思路萬千並不是惟一,請結合具體案例編寫測試用例驗證正確性。同時也請進一步思考是否有更優的算法。指針

參考資料:
https://leetcode-cn.com/problems/3sum/solution/hua-jie-suan-fa-15-san-shu-zhi-he-by-guanpengchn/code

相關文章
相關標籤/搜索