給定一個整數數組,在該數組中,尋找三個數,分別表明三角形三條邊的長度,問,能夠尋找到多少組這樣的三個數來組成三角形?
樣例 1:
樣例 2:
輸入: [4, 4, 4, 4]
輸出: 4
解釋:
任何三個數均可以構成三角形
因此答案爲 C(3, 4) = 4
題目理解
- 咱們先考慮「三條邊能構成三角形」的充分必要條件。咱們首先想到的是「三角形的任意兩邊之和大於第三邊,三角形的任意兩邊之差小於第三邊」。若是從這個角度理解,代碼編寫比較麻煩,由於「任意」二字就要求咱們去檢驗各類組合。
- 若是咱們仔細分析一下這個條件,就不難證實它等效於「較短的兩邊之和大於最長邊」。對於升序排列的三個數[a, b, c],咱們只需判斷a + b > c是否成立,就知道它們是否能構成三角形。
解題思路
- 最直觀的方法是暴力法,三重循環枚舉,時間複雜度爲O(n^3)。
- 若是先將數組排好序,二重循環固定較短兩邊a和b,而後再利用二分查找找到最大的知足a + b > c的c,這樣能夠將時間複雜度優化至O(n^2logn)
- 這裏咱們採用雙指針方法,能夠繼續下降時間複雜度。首先固定最大邊的位置 i,而後在 [0, i-1]之間利用雙指針找到知足條件的三邊。時間複雜度爲O(n^2)。
算法流程
- 首先對數組進行升序排列。
- 從右向左遍歷最大邊,固定最大邊的位置i
- 創建雙指針left和right,初始分別指向0和i-1
- 若是S[left] + S[right] > S[i],說明三者能夠構成三角形。與此同時,最小邊的索引爲left+1, left+2,...,right-1時,都能與S[right]和S[i]構成三角形。因此知足條件的三角形找到了right-left個。而後right指針左移進入下一輪。
- 若是S[left] + S[right] <= S[i],說明不能構成三角形。left指針右移進入下一輪。
複雜度分析
- 時間複雜度爲O(n^2)。外層遍歷最大邊是n,內層循環移動雙指針是n,因此總複雜度爲O(n^2)。
- 空間複雜度爲O(1),只需佔用常量空間。
public class Solution {
public int triangleCount(int[] S) {
int res = 0;
int left = 0, right = S.length - 1;
Arrays.sort(S);
for (int i = 0; i < S.length; i++) {
left = 0;
right = i - 1;
while (left < right) {
if (S[left] + S[right] > S[i]) {
res += (right - left);
right --;
}
else {
left ++;
}
}
}
return res;
}
}