leetcode 611.有效三角形的个数

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

示例 1:

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

注意:

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

我的解法:

  最容易想到的是三个数满足条件:任意两边之和大于第三边。只要写一个三重循环遍历所有情况,就能得知答案。

int triangleNumber(vector<int>& nums) {
        int n=nums.size();
        int count=0;
        for(int i=0;i<n-2;i++)
            for(int j=i+1;j<n-1;j++)
                for(int k=j+1;k<n;k++)
                {
                    //任意两边之和大于第三边
                    if((nums[i]+nums[j]>nums[k])
                      &&(nums[j]+nums[k]>nums[i])
                      &&(nums[k]+nums[i]>nums[j]))
                        count++;
                }
        return count;
    }

结果是正确的,但是效率太低了,测试耗时1800ms。

考虑它的另一个等价条件:最长边小于其余两边之和。在循环体中挑选最长的边,依然是件很复杂的事情,不如事先将数组排序,这样选出来的边无需比较就知道他们的长度关系了。这样做大大减少了条件判断的次数,然而时间复杂度仍旧是n立方的。

如果要把每种情况都考虑到,一一判断,那么至少需要判断C(n,3)次,时间复杂度必定是O(n^3)。但实际上不用求出每个满足条件的每种情况,只要求出满足条件的情况的数目。这样,在确定了两条次长边a,b之后,我们可以确定最长边的长度c区间:max(a,b)<c<a+b,进而确定这个区间中有多少个元素即可。

int triangleNumber(vector<int>& nums) {
        //先排序
        sort(nums.begin(),nums.end());
        auto end=nums.end();
        int count=0;
        for(auto i=nums.begin();i<end-2;i++)
            for(auto j=i+1;j<end-1;j++)
            {
                //寻找最大边可能在的区间[a,b)
                auto a=j+1;
                auto b=upper_bound(a,end,(*i)+(*j)-1);
                count+=b-a;
            }
        return count;
    }

时间复杂度是 O(n^2*logn),效率提高不少,测试耗时50ms。

暂时想不到更好的办法,去看了别人最快的算法实现,是这样的:

int triangleNumber(vector<int>& nums) {
        vector<int> snums(nums);
        sort(snums.begin(),snums.end());
        int count = 0;
        for(int n = nums.size(),k = n - 1;k > 1;k--){
            int i = 0;
            int j = k - 1;
            while(i < j)
                if(snums[i] + snums[j] > snums[k])
                    count += --j - i + 1;
                else
                    i++;
        }
        return count;
    }

揣摩了一下,他的思路是这样的:

在固定最长边c的情况下,对于每个次长边b,求出所有最短边a的可能总数。而b与a存在如下制约关系:

如果a和b是一组可能的解,那么所有x(其中x属于[a,b))和y(其中y属于[b,c))都是可能的解;

如果a和b是一组不可能的解,那么所有的x(其中x属于(0,a])和y(其中y属于[b,c))都是不可能的解。

再加上构思设计的算法,将时间复杂度降到了O(n^2)

猜你喜欢

转载自blog.csdn.net/liusiweix/article/details/83930904