1. 程式人生 > >leetcode 611.有效三角形的個數

leetcode 611.有效三角形的個數

給定一個包含非負整數的陣列,你的任務是統計其中可以組成三角形三條邊的三元組個數。

示例 1:

輸入: [2,2,3,4]
輸出: 3
解釋:
有效的組合是: 
2,3,4 (使用第一個 2)
2,3,4 (使用第二個 2)
2,2,3

注意:

  1. 陣列長度不超過1000。
  2. 數組裡整數的範圍為 [0, 1000]。

我的解法:

  最容易想到的是三個數滿足條件:任意兩邊之和大於第三邊。只要寫一個三重迴圈遍歷所有情況,就能得知答案。

int triangleNumber(vector<int>& nums) {
        int n=nums.size();
        int count=0;
        for(int i=0;i<n-2;i++)
            for(int j=i+1;j<n-1;j++)
                for(int k=j+1;k<n;k++)
                {
                    //任意兩邊之和大於第三邊
                    if((nums[i]+nums[j]>nums[k])
                      &&(nums[j]+nums[k]>nums[i])
                      &&(nums[k]+nums[i]>nums[j]))
                        count++;
                }
        return count;
    }

結果是正確的,但是效率太低了,測試耗時1800ms。

考慮它的另一個等價條件:最長邊小於其餘兩邊之和。在迴圈體中挑選最長的邊,依然是件很複雜的事情,不如事先將陣列排序,這樣選出來的邊無需比較就知道他們的長度關係了。這樣做大大減少了條件判斷的次數,然而時間複雜度仍舊是n立方的。

如果要把每種情況都考慮到,一一判斷,那麼至少需要判斷C(n,3)次,時間複雜度必定是O(n^3)。但實際上不用求出每個滿足條件的每種情況,只要求出滿足條件的情況的數目。這樣,在確定了兩條次長邊a,b之後,我們可以確定最長邊的長度c區間:max(a,b)<c<a+b,進而確定這個區間中有多少個元素即可。

int triangleNumber(vector<int>& nums) {
        //先排序
        sort(nums.begin(),nums.end());
        auto end=nums.end();
        int count=0;
        for(auto i=nums.begin();i<end-2;i++)
            for(auto j=i+1;j<end-1;j++)
            {
                //尋找最大邊可能在的區間[a,b)
                auto a=j+1;
                auto b=upper_bound(a,end,(*i)+(*j)-1);
                count+=b-a;
            }
        return count;
    }

時間複雜度是 O(n^2*logn),效率提高不少,測試耗時50ms。

暫時想不到更好的辦法,去看了別人最快的演算法實現,是這樣的:

int triangleNumber(vector<int>& nums) {
        vector<int> snums(nums);
        sort(snums.begin(),snums.end());
        int count = 0;
        for(int n = nums.size(),k = n - 1;k > 1;k--){
            int i = 0;
            int j = k - 1;
            while(i < j)
                if(snums[i] + snums[j] > snums[k])
                    count += --j - i + 1;
                else
                    i++;
        }
        return count;
    }

揣摩了一下,他的思路是這樣的:

在固定最長邊c的情況下,對於每個次長邊b,求出所有最短邊a的可能總數。而b與a存在如下制約關係:

如果a和b是一組可能的解,那麼所有x(其中x屬於[a,b))和y(其中y屬於[b,c))都是可能的解;

如果a和b是一組不可能的解,那麼所有的x(其中x屬於(0,a])和y(其中y屬於[b,c))都是不可能的解。

再加上構思設計的演算法,將時間複雜度降到了O(n^2)