15. 3Sum[M]三數之和


題目

Given an array nums of n integers, are three 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]]


思路

雙指針法變種——三指針法(這里的指針指的是數組下標)

  • 要保證三個數a+b+c=0;
    • 至少要保證有一個數是0或者負數,
    • 但是由於數組是亂序排列的,很難直接判斷是否有0或負數,於是想到將數組排序
  • 將等式改寫為b+c = -a,如何找到
    • 首先保證a是非正數(0或負數)
    • 如何找到b和c使之與-a相等?
      • 定義中間指針p2、尾指針p3,移動的方向為往中間移動
圖1:指針移動示意圖
  • 不能有重復結果
    • 在最外層循環時,跳過已經判斷過的數字
    • p2、p3往中間移動時,跳過重復元素

於是
Step1:將數組排序
Step2:以第一個數p1作為最外層循環,其中如果第一個數如果為正,說明和不可能為0
Step3:定義中間指針p2,尾指針p3,

  • 如果num[p2] + num[p3] > -nums[p1],則說明和太小了,應該往數值大的方向的移動,p2++
  • 如果num[p2] + num[p3] < -nums[p1],則說明和太大了,應該往數值小的方向的移動,p3--
  • 如果num[p2] + num[p3] = -nums[p1],將結果保存,同時將p2、p3往中間移動,為了保證結果的唯一性,需要跳過重復元素

Tips

列表方法(python)

方法是作用於Python中特定類型對象的函數。列表類型擁有9個只作用於列表的方法,分為兩類

  • 改變列表的方法
  • 不改變列表的方法

以列表aList = [ 2, 1, 3, 'a', 4 ]為例(假設每個方法下的例子都是獨立的,不會互相影響):

1. 不修改列表的方法
  • index(x)返回列表中與x值相等的第一個元素的索引。如果在列表中沒有找到這樣的元素,Python將報錯。
aList.index(3)   #輸出2
  • count(x)返回列表中x出現的次數。如果列表中不包含x,返回0。
aList.count(1)    #輸出1
2. 修改列表的方法
  • append(x)在列表的末尾添加元素。列表長度增加1,如果append的參數時列表,則該列表(包括方括號)將作為單個元素加入列表中。
aList.append(5)     #輸出是[2, 1, 3, 'a', 4, 5]
aList.append([5, 6, 7]) #輸出是[2, 1, 3, 'a', 4,  [5, 6, 7] ]
  • pop()刪除列表末尾的元素,並返回此元素。列表變短,少了一個元素。如果指定索引值,則array.pop(index)將刪除該索引位置的元素並返回該項。
aList.pop()    #輸出4
  • extend(A)需要一個集合作為參數。將該集合中的每個元素添加到列表的末尾,從而擴展列表。
anotherList=[5, 6]
aList.extend(anotherList)  #輸出是[2, 1, 3, 'a', 4, 5, 6]
  • insert(index, x)在指定位置插入元素。第一個參數是元素插入前的索引。如果x是一個列表,則該列表(包括方括號)將作為單個元素加入列表中。
aList.insert(2, 'b')     #輸出是[2, 1, 'b', 3, 'a', 4]
  • remove(x)刪除列表中第一個值為x的元素。如果沒有該元素,將出錯。
aList.remove(2)     #輸出是[1, 3, 'a', 4]
  • sort()將列表中的元素進行排序。與sorted函數比較,sorted返回排好序的列表,但是不改變原列表。如果要對列表的列表進行排序,則只考慮每個列表的首元素。
aList.sort()     #輸出是[1, 2, 3, 4, 'a']
  • reverse()將列表中的元素反向排列。
aList.reverse()     #輸出是['a', 4, 3, 2, 1]

C++

vector<vector<int>> threeSum(vector<int>& nums) {

  vector<vector<int> > resVec;
  sort(nums.begin(),nums.end());  //將nums從小到大排序

  for(int p1=0;p1<nums.size();p1++){
    if(nums[p1] >0)  //如果第一個數為正數,說明肯定不存在三個數
      return resVec;
    if(p1>0 && nums[p1] == nums[p1-1])  //由於結果需要唯一性,故去除nums中的重復元素
      continue;
    int p2 = p1+1;//中間指針
    int p3 = nums.size()-1;//尾指針
    while(p2<p3){
      int a = nums[p1];//非正
      int b = nums[p2];
      int c = nums[p3];
      if(b+c== -a){
        vector<int> tempVec(3);
        tempVec[0] = a;
        tempVec[1] = b;
        tempVec[2] = c;
        resVec.push_back(tempVec);
        while (p2 < p3 && nums[p2] == nums[p2 + 1])  //去除重復元素
           p2++;
        while (p2 < p3 && nums[p3 - 1] == nums[p3])  //去除重復元素
           p3--;
        p2++;
        p3--;       
      }
      else if(b+c < -a){   //如果b+c之和小於-a,說明和太小了,應該往數值大的方向的移動
        p2++;
      }
      else{  //反之,如果b+c之和大於-a,說明和太大了,應該往數值小的方向的移動
        p3--;
      }
    }       
  }
  return resVec;
}

Python

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        
        nums.sort() 
        result = [  ]
        
        for p1 in range(len(nums)):
            if nums[p1] > 0:
                return result
            if p1 > 0 and nums[p1] == nums[p1-1]:
                continue
            
            p2 = p1 + 1
            p3 = len(nums) - 1
            
            while p2 < p3:
                a = nums[p1]
                b = nums[p2]
                c = nums[p3]
                
                if(b + c == -a):
                    result.append([a, b, c])
                    while p2 < p3 and nums[p2] == nums[p2+1]:
                        p2 += 1
                    while p2 < p3 and nums[p3-1] == nums[p3]:
                        p3 -= 1
                    p2 += 1
                    p3 -= 1
                elif(b + c < -a):
                    p2 += 1
                else:
                    p3 -= 1
                     
        return result
             

參考

[1] Python入門經典


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM