每日OJ题_算法_双指针⑤_力扣611. 有效三角形的个数

目录

力扣611. 有效三角形的个数

解析代码


力扣611. 有效三角形的个数

难度 中等

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

示例 1:

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

示例 2:

输入: nums = [4,2,3,4]
输出: 4

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000
class Solution {
public:
    int triangleNumber(vector& nums) {

    }
};

解析代码

暴力法:(这里代码就不写了,时间复杂度是O(N^3))

三层 for 循环枚举出所有的三元组,并且判断是否能构成三角形。

虽然说是暴力求解,但还是可以优化一下:

如果能构成三角形,需要满足任意两边之和要大于第三边。但是实际上只需让较小的两条边之和大于第三边即可。因此我们可以先将原数组排序,然后从小到大枚举三元组,一方面省去枚举的数量,另一方面方便判断是否能构成三角形。

双指针:时间复杂度是O(N^2)

先将数组排序。根据暴力法中的优化思想,我们可以固定一个“最长边”,然后在比这条边小的有序数组中找出一个二元组,使这个二元组之和大于这个最长边。由于数组是有序的,我们可以利用“对撞指针”来优化。
设最长边枚举到 i 位置,区间 [left,right] 是 i 位置左边的区间 (也就是比它小的区间):

如果 nums[left] + nums[right] > nums[i] ,
说明 [left,right - 1] 区间上的所有元素均可以与 nums[right] 构成比nums[i] 大的二元组,
满足条件的有 right - left 种,
此时 right 位置的元素的所有情况相当于全部考虑完毕, 减减right ,进入下一轮判断,
如果 nums[left] + nums[right] <= nums[i] ,
说明 left 位置的元素是不可能与 [left + 1,right] 位置上的元素构成满足条件的二元组,此时
left 位置的元素可以舍去, 加加left 进入下轮循环。

双指针代码:

class Solution {
public:
    int triangleNumber(vector& nums) {
        sort(nums.begin(), nums.end());
        int ret = 0, pos = nums.size() - 1; // 固定的数
        for(int i = pos; i >= 2; --i) // 因为至少三个数,所以大于等于2
        {
            int left = 0, right = i - 1;
            while(left < right)
            {
                if(nums[left] + nums[right] > nums[i])
                {
                    ret += (right - left);
                    --right;
                }
                else
                {
                    ++left;
                }
            }
        }
        return ret;
    }
};

你可能感兴趣的:(算法,leetcode,c++)