LeetCode每日一题 611.有效三角形的个数

165 阅读2分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

611. 有效三角形的个数

题目

给定一个包含非负整数的数组,你的任务是统计其中可以组成三角形三条边的三元组个数。

示例 1:

输入: [2,2,3,4]
输出: 3
解释:
有效的组合是: 
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3

注意:

  1. 数组长度不超过1000。
  2. 数组里整数的范围为 [0, 1000]。

方法一

排序+二分:可以组成三角形的条件是,任意两边之和大于第三边,我们可以分别枚举三个点,然后判断是否满足组成三角形的条件,但是这样的事件复杂度就是O(n^3),会超时。所以,可以稍微的优化一下;

  • 枚举三个点,我们变成枚举两个点,第三个通过二分来确定(这样时间复杂度就变成了O(n^2logn),使用二分的条件是数组单调,所以得先排序;
  • 枚举第一二个点,在对后面的元素进行二分,找出最大的满足组成三角形条件的点,更新答案;
class Solution {
    public int triangleNumber(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
​
        int res = 0;
        for (int i = 0; i < n - 2; i ++ ) 
            for (int j = i + 1; j < n - 1; j ++ )
            {
                int l = j + 1, r = n - 1;
                while (l < r) {
                    int mid = (l + r + 1) >> 1;
                    if (nums[i] + nums[j] > nums[mid]) l = mid;
                    else r = mid - 1;
                }
​
                if (l == j + 1) {
                    if (nums[i] + nums[j] > nums[l])
                        res ++;
                }
                else res += l - j;
            }
​
        return res;
    }
}

时间复杂度: O(n^2logn)

空间复杂度: O(logn)

方法二

双指针:我们可以发现当三个元素中的第二个元素往后移的过程中,第三个元素也是跟着往后移的,所以可以用双指针;

  • 枚举第一个元素的位置
  • 定义两个指针,jk
  • nums[i] +nums[j] > nums[k]时,k往后移;
  • nums[i] +nums[j] <= nums[k]时,计算kj之前的元素,更新答案,并且j往后移;
class Solution {
    public int triangleNumber(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
​
        int res = 0;
        for (int i = 0; i < n; i ++ ) {
            int k = i;
            for (int j = i + 1; j < n; j ++ ) {
                while(k + 1 < n && nums[k + 1] < nums[i] + nums[j]) k ++;
                res += Math.max(k - j, 0);
            }
        }
​
        return res;
    }
}

时间复杂度: O(n^2)

空间复杂度: O(1)