leetcode 611.有效三角形的個數
阿新 • • 發佈:2018-11-22
給定一個包含非負整數的陣列,你的任務是統計其中可以組成三角形三條邊的三元組個數。
示例 1:
輸入: [2,2,3,4] 輸出: 3 解釋: 有效的組合是: 2,3,4 (使用第一個 2) 2,3,4 (使用第二個 2) 2,2,3
注意:
- 陣列長度不超過1000。
- 數組裡整數的範圍為 [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)