在給定的一組代表棍子長度的數組中,找到三根棍子,可以構成三角形,並且該三角形是能組成的三角形中周長最大的。
拿到這題,首先最能想到的一個方法就是三重循環的方法,把所有三根棍子的組合羅列出來,並對其中能組成三角形的周長與之前找到的最大周長比較,大於原先的最大周長,則更新最大周長。(判斷構成三角形的充要條件:最長棍子的長度<其餘兩個棍子長度之和)
但是簡單的方法往往帶來跟多的消耗,這裏三重循環的時間複雜度爲O(n^3),雖說能通過一些方法不去羅列重複的組合(如3,4,5和,3,5,4和4,5,3等等是一個組合),但是複雜度仍然爲O(n^3)。那麼可不可以找到一個更簡單的方法呢,答案是可以的。
方法就是先對數組進行排序,並利用貪心算法先取得最長的一根棍子,之後的兩根依次取最長的棍子,如果這樣構不成三角形,那麼以最長棍子最爲三角形中最長的一條邊是不行的,至於爲什麼這樣,可以舉個例子,在2,3,4,5,7,8,20中我們按照剛纔的想法依次找到了20,8,7但是20>7+8,所以20,8,7構不成三角形,如果這時不放棄20,仍將20作爲三角形中最長的邊,那麼在剩下的棍子中肯定找不出滿足條件的兩個棍子,因爲7和8就是除了20以外最長的根子了,他倆都無法和20組成三角形,那麼其他的兩根組合肯定就不行了.
依據這種思想,我們便有了以下的解題源碼:
#include<cstdio>
#include<cstdlib>
#include <algorithm>
using namespace std;
const int MAX_N=100;
int main()
{
int n;
bool isOk=false;
int a[MAX_N];
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n); //對數組指定範圍進行升序排序
for(int i=n-1;i>1;i--)
{
if(a[i]<a[i-1]+a[i-2])
{
isOk=true;
printf("最大周長爲%d=%d+%d+%d\n",a[i]+a[i-1]+a[i-2],a[i],a[i-1],a[i-2]);
break;
}
}
if(!isOk)
printf("無法構成三角形\n");
return 0;
}
這種方法在排序後,只有一層循環,循環的時間複雜度是O(n),但是排序函數的時間複雜度最小爲(nlog2(n)),所以整體的時間複雜度爲(nlog2(n)),遠遠小於原來的O(n^3).
PS:兩本的《挑戰》帶着一起看,基礎知識和具體的算題共同學習,感覺效果也不錯~