这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
题目
给定一个包含非负整数的数组,你的任务是统计其中可以组成三角形三条边的三元组个数。
示例
输入: [2,2,3,4]
输出: 3
解释:
有效的组合是:
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3
提示
数组长度不超过1000数组里整数的范围为 [0, 1000]
解题思路
- 三边组成三角形的情况有如下三种,设
a <= b <= c:- a + b > c
- b + c > a
- a + c > b
(注: 这一点还需满足 a - c < b才能成立)
- 为了避免第三种情况的判断,我们可以先将数组进行排序,使其成立情况局限于前面两种
代码实现
暴力法
- 最容易想到的方法,就是使用暴力法,嵌套3层循环,罗列出每一个组合,计算结果后进行累加
class Solution {
public int triangleNumber(int[] nums) {
// 先将数组排序
Arrays.sort(nums);
int ans = 0, n = nums.length;
// 三层遍历,逐组进行比较判断
for(int i = 0; i < n - 2; ++i){
for(int j = i + 1; j < n - 1; ++j){
int k = j + 1;
while(k < n && nums[i] + nums[j] > nums[k++]){
++ans;
}
}
}
return ans;
}
}
复杂度分析
- 时间复杂度:O()
- 空间复杂度:O(log)
双指针
- 暴力法虽然简单,不过在时间方面的开销太大了,这里我们还可以利用排好序之后的特性对它进行一个优化:
- 当 + > 时, + 也必定大于
- 那么我们就可以使用双指针解法,定义两个指针变量,一个指向
j,一个指向k,每次都将k指针推到符合 + > 的最边界处,再移动j指针进行下一轮的比较,公式为:k - j - 1 - 当
j >= k导致k - j - 1为负数的情况,需累加0
class Solution {
public int triangleNumber(int[] nums) {
// 将数组进行排序
Arrays.sort(nums);
int ans = 0, n = nums.length;
// i最大为 n - 2
for(int i = 0; i < n - 2; ++i){
// k最小为 i + 2
int k = i + 2;
// 遍历 [i + 1, n - 1] 区间
for(int j = i + 1; j < n - 1; ++j){
// 将k指针移动到符合区间的最边界处
while(k < n && nums[k] < nums[i] + nums[j]){
++k;
}
// 累加满足条件的区间,同时做负数情况的处理
ans += Math.max(k - j - 1, 0);
}
}
return ans;
}
}
复杂度分析
- 时间复杂度:O()
- 空间复杂度:O(log)
最后
文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!
如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!