LeetCode 611. Valid Triangle Number
题目描述
Given an array consists of non-negative integers, your task is to count the number of triplets chosen from the array that can make triangles if we take them as side lengths of a triangle.
Example 1:
Input: [2,2,3,4]
Output: 3
Explanation:
Valid combinations are:
2,3,4 (using the first 2)
2,3,4 (using the second 2)
2,2,3
Note:
- The length of the given array won't exceed 1000.
- The integers in the given array are in the range of [0, 1000].
解题思路
首先想到的是暴力枚举所有的三元组,但是三层循环、并且每个三元组都需要三次三角不等式判断,肯定是不可接受的,所有我们可以有以下优化:
- 可以先排序,然后 i<j<k 的约束条件下,就只需要判断
nums[i] + nums[j] > nums[k]
这一个不等式就可以了; - 又注意到数组有序,这样当某一个k不满足条件,后续的k都将不满足条件,可以提前结束 k 循环;
- 在有序数组中,前半段满足条件后半段不满足条件的判断,可以用二分查找进一步优化。
参考代码
对于优化1和优化2,我们有以下代码:
/*
* @lc app=leetcode id=611 lang=cpp
*
* [611] Valid Triangle Number
*/
// @lc code=start
class Solution {
public:
int triangleNumber(vector<int>& nums) {
size_t n = nums.size();
int cnt = 0;
sort(nums.begin(), nums.end());
for (int i=0; i+2<n; i++) {
for (int j=i+1; j+1<n; j++) {
for (int k=j+1; k<n; k++) {
if (nums[i] + nums[j] <= nums[k]) {
break;
}
cnt ++;
}
}
}
return cnt;
} // AC, O(N^3)
};
// @lc code=end
加入优化3,代码如下:
/*
* @lc app=leetcode id=611 lang=cpp
*
* [611] Valid Triangle Number
*/
// @lc code=start
class Solution {
public:
int triangleNumber(vector<int>& nums) {
size_t n = nums.size();
int cnt = 0;
sort(nums.begin(), nums.end());
for (int i=0; i+2<n; i++) {
for (int j=i+1; j+1<n; j++) {
auto start = nums.begin()+j+1;
auto it = lower_bound(start, nums.end(), nums[i]+nums[j]);
cnt += it - start;
}
}
return cnt;
} // AC, O(N^2 * logN)
// lower_bound 二分查找返回元素第一次出现位置,或者第一个大于该元素的位置
};
// @lc code=end