Leetcode算法学习日志-611 Valid Triangle Number

来源:互联网 发布:苹果排雷软件 编辑:程序博客网 时间:2024/06/05 10:14

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: 3Explanation:Valid combinations are: 2,3,4 (using the first 2)2,3,4 (using the second 2)2,2,3

Note:

  1. The length of the given array won't exceed 1000.
  2. The integers in the given array are in the range of [0, 1000].

题意分析

给一个数组,求该数组的子集,使得子集元素能构成三角形,求三角形个数。

解法分析

本题首先想到的是采用深度优先搜索(回溯)的方法,构造子集树,来得到所有满足条件的三元组,此时要注意,如果没有剪枝函数,只有上界函数,回溯法相当于暴力破解法,因为所有的可能的三元组合都被找到,只是判断了下是否能够成三角形,这种方法会超时。

为了加入剪枝操作,考虑三角形两边之和大于第三边的特性,如果对数据首先进行排序,则当两个较小的数(在子集树上部)之和小于第三个数时,它们之和一定小于更大的数(子集树下层),这样就避免了一些递归搜索操作。注意,剪枝造成的效果就是在pop之后,原本需要调用back_track()进入右子树,但如果剪枝操作认定右子树的所有数据都不能得到所求解时,就可以提前return,跳过函数调用(右子树递归调用完上一级函数也会return,所以剪枝函数的作用就是判断条件成立后提前return,减少调用次数)。C++代码如下:

class Solution {private:vector<int> temp;vector<int> nums;int count;int n;int sig;public:void back_track(int k) {sig = 1;if (temp.size() == 3) {if ((temp[0] + temp[1])>temp[2]) {count++;return;}else {sig = 0;//temp.pop_back();return;}}if (k>n)return;temp.push_back(nums[k - 1]);/*for (auto ww : temp)cout << ww << ends;cout << endl;*/back_track(k + 1);temp.pop_back();if (sig == 0){sig = 1;//remenber to be 1return;}elseback_track(k + 1);}int triangleNumber(vector<int>& number) {nums = number;sort(nums.begin(), nums.end());n = nums.size();count = 0;back_track(1);return count;}};
无论如何,回溯法是一种近似遍历的方法,复杂度较高,本题有一种巧妙的思路,充分运用两边之和大于第三边的性质,并且,如果对数据进行排序后,如果两个较小数据之和大于较大数据,则一定能得到它们是三角形的边,因为两个较小边之差必然小于较大边,这两个条件结合在一起就能保证三角形的性质。

从最大数开始遍历,定义两个下标l和r,r=i-1,C++代码如下:

class Solution {public:    int triangleNumber(vector<int>& nums) {        sort(nums.begin(), nums.end());                int count = 0, n = nums.size();        for (int i = n-1; i >= 2; --i) {            int l = 0, r = i-1;            while (l < r) {                if (nums[l]+nums[r] > nums[i]) {                    count += r - l;                    -- r;                } else                    ++ l;            }        }        return count;    }};
例如{2,2,3,4},当最大数为4时,较小边为2和3,且2+3>4,它们能构成三角形,由于第一个2右边的数一定大于等于它,则2和3中间的数与3,4一起一定能构成三角形,这也就是下面两句代码的含义:

if (nums[l]+nums[r] > nums[i]) {            count += r - l;
由于r和l是相向移动,复杂度为O(n),总的算法复杂度为O(n^2)。


原创粉丝点击