1. 程式人生 > >演算法練習week2--leetcode15

演算法練習week2--leetcode15

題目介紹


演算法設計

第一階段

三重for迴圈,從前到後遍歷所有情況,時間複雜度為O(n^3)。

vector< vector<int> > threeSum(vector<int>& nums){
    vector< vector<int> >sum;
    vector<int>temp(3);
    int x = 0;
    int num1,num2,num3;
    for(int i = 0;i < nums.size()-2;i++){
        num1 = nums[i];
        for(int j = i+1;j < nums.size()-1;j++){
            num2 = nums[j];
            for(int k = j+1;k < nums.size();k++){
                num3 = nums[k];
                if(num1+num2+num3 == 0){
                    temp[0] = num1;
                    temp[1] = num2;
                    temp[2] = num3;
                    sum.push_back(temp);
                }
            }
        }
    }
    return sum;
}

這種演算法過於基礎直接採用遍歷進行問題求解,主要存在一下兩個問題:

  • 時間複雜度達到了O(n^3),計算量太大
  • 無法避免題目中重複陣列的問題,只能通過進行處理。基本處理步驟如下:
  1. 對每個三元組進行排序,sort或者set,時間複雜度為O(1)
  2. 用兩重for迴圈進行刪重,時間複雜度為O(n^2)

第二階段

我上週在leetcode上做到的一道題給了我啟發。題目是:給定一個有序陣列,求出和為0的所有二元組,二元組不可相同。

上一題為了解決二元組相同重複,設定了兩個指標一頭一尾,一個從前往後走,一個從後往前走,避免了陣列相同的問題。

其時間複雜度為O(n/2);

其程式碼實現如下:

vector< vector<int> > TwoSum(vector<int>& nums){
    vector< vector<int> >sum;
    vector<int>temp(2);
    int x = 0;
    int num1,num2;
    sort(nums.begin(),nums.end());
    int i = 0;
    int j = nums.size()-1;
    while(i< j){
       if(nums[i] + nums[j] == 0){
            temp[0] = nums[i];
            temp[1] = nums[j];
            sum.push_back(temp);
       }
       i++;
       j--;
    }
    return sum;
}

在第一階段三重迴圈基礎上改進,a+b+c = 0這個等式可以改進為a+b = -c;即外迴圈將c固定,內迴圈利用TowSum()函式尋找和為-c的二元組,拼在一起即可。這樣此種演算法的時間複雜度僅為O(n^2),且無需後去去重操作。修改後的程式碼為,其總程式碼只有20行,十分簡單。

vector< vector<int> > ThreeSum(vector<int>& nums){
    vector< vector<int> >sum(0,vector<int>(3));
    vector<int>temp(3);
    int x = 0;
    sort(nums.begin(),nums.end());
    for(int k = 0;k < nums.size()-2;k++){
        temp[0] = nums[k];
        int i = k+1;
        int j = nums.size()-1;
        while(i < j ){
            if(nums[i] + nums[j] == 0-nums[k]){
                temp[1] = nums[i];
                temp[2] = nums[j];
                sum.push_back(temp);
            }
            i++;
            j--;
        }
    }
    return sum;
}

一些坑

在寫內層迴圈時判斷是否存在和為-c的二元組時,在兩個下標i,j的邊緣條件時,我們實在無需考慮得太複雜無需考慮陣列長度奇數或偶數的情況分開討論,只需保證從前往後走的下標始終在從後往前走的下標前即可,即簡單的i < j即可。下面是錯誤的示範:

while((i + ((nums.size()-1)%2)) != j){