给定一个包含非负整数的数组,你的任务是统计其中可以组成三角形三条边的三元组个数。
示例1:
1 2 3 4 5 6 7 输入: [2,2,3,4] 输出: 3 解释: 有效的组合是: 2,3,4 (使用第一个 2) 2,3,4 (使用第二个 2) 2,2,3
解题思路 1.暴力 这道题要求枚举符合条件的三元组,最简单的方法是通过三层循环直接枚举所有的组合,对三边都进行 a+b<c && a+c<b && b+c<a 的判断,累加求出个数。
2.排序+二分 首先我们对数组进行排序,对于已排序数组,即三元组a < b < c,当且仅当 a + b > c时符合条件,因此我们可以通过两层循环固定a,b,对于c在有序区间中找到小于a+b的最大值,则(b,c]中的元素个数即为当前a,b对应的解个数,累加即可。
时间复杂度为 $n^2log(n)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution { public int triangleNumber (int [] nums) { Arrays.sort(nums); int n = nums.length; int res = 0 ; int left, right, mid; for (int i = 0 ; i < n - 2 ; i++){ for (int j = i + 1 ; j < n - 1 ; j++){ left = j + 1 ; right = n - 1 ; while (left < right){ mid = (left + right + 1 ) / 2 ; if (nums[mid] >= nums[i] + nums[j]){ right = mid - 1 ; }else { left = mid; } } if (nums[left] < nums[i] + nums[j]) res += left - j; } } return res; } }
3.排序+双指针 依然首先对数组排序,我们考虑a + b > c的条件,我们可以先固定最长边c,通过双指针来寻找a,b。一个关键点在于反向遍历c,每一个c对应的left和right指针,left=0,right=k-1。 如果nums[left] + nums[right] > c,则[left, right]区间的所有数符合条件,right左移; 如果nums[left] + nums[right] <= c,则left右移,直到大于c。 最后left于right碰撞,即已经找完当前c对应的所有解。
时间复杂度为 $n^2$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int triangleNumber (int [] nums) { Arrays.sort(nums); int n = nums.length; int res = 0 ; for (int i = n-1 ; i>=2 ; i--){ int right = i-1 ; int left = 0 ; while (left < right){ if (nums[left] + nums[right] > nums[i]){ res += right - left; right--; }else { left++; } } } return res; } }