给定一个整数数组,在该数组中,寻找三个数,分别表明三角形三条边的长度,问,能够寻找到多少组这样的三个数来组成三角形?
样例 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;
}
}