leetcode 611. Valid Triangle Number

257 篇文章 17 订阅

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:

  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].
这道题我用map会TLE,改成数组就AC了。map.get[i] 的搜索效率低于数组[i]的获取效率?

public int triangleNumber(int[] nums) {
	int[] map=new int[1001];
	for(int i=0;i<nums.length;i++){
		map[nums[i]]++;
	}
	int count=0;
	for(int i=0;i<nums.length-2;i++){
		map[nums[i]]--;
		for(int j=i+1;j<nums.length-1;j++){
			map[nums[j]]--;
			//只找j后面的数
			int one=nums[i];
			int two=nums[j];
			int min=Math.abs(one-two)+1;
			int max=one+two-1;
			for(int k=min;k<=max;k++){
				count+=map[k];
			}
		}
		//又加回去
		for(int j=i+1;j<nums.length-1;j++){
			map[nums[j]]++;
		}
	}
	return count;
}
我发现大神的解法第一步都是:先排序。

假设 a 是最长边,b and c 是较短的两边,要形成三角形,需要满足 len(b) + len(c) > len(a).

思路是排序之后,从数字末尾开始往前遍历,将left指向首数字,将right指向之前遍历到的数字的前面一个数字,然后如果left小于right就进行循环,循环里面判断如果left指向的数加上right指向的数大于当前的数字的话,那么right到left之间的数字都可以组成三角形,这是为啥呢,相当于此时确定了i和right的位置,可以将left向右移到right的位置,中间经过的数都大于left指向的数,所以都能组成三角形。加完之后,right自减一。如果left和right指向的数字之和不大于nums[i],那么left自增1,参见代码如下:

public class Solution {
    public int triangleNumber(int[] nums) {
        int result = 0;
        if (nums.length < 3) return result;
        
        Arrays.sort(nums);

        for (int i = 2; i < nums.length; i++) {//令nums[i]为最长边
            int left = 0, right = i - 1;//nums[right]为第二长边,nums[left]是最短边
            while (left < right) {
                if (nums[left] + nums[right] > nums[i]) {//当前已经能够满足短+短>长
                    result += (right - left);//那么[left,right)范围内的数作为最短边仍然能满足
                    right--;//改变第二长边
                }
                else {
                    left++;//当前不能满足短+短>长,增加最短边
                }
            }
        }
        
        return result;
    }
}
这道题有solutions: https://leetcode.com/problems/valid-triangle-number/solution/

Approach #2 Using Binary Search [Accepted]

Algorithm

令 i<j<k,那么要使得nums[k]>nums[i]+nums[j],索引 k 有一个右边的临界点。任何索引只要>=该临界点,就肯定不会满足这个不等式。

如果我们找到了这个临界点,设为 k,我们就可以保证在 (j+1, k-1)索引范围内的数能够满足上述不等式。在这范围内的数字都能够作为 ( i , j ) pair 的第三边,数量是 (k-1) - (j+1) + 1 = k - j - 1.

因为 nums数组已经被排序了,我们可以使用 Binary Search 来找到 k 的右临界点。

Java

public class Solution {
    int binarySearch(int nums[], int l, int r, int x) {
        while (r >= l && r < nums.length) {
            int mid = (l + r) / 2;
            if (nums[mid] >= x)
                r = mid - 1;
            else
                l = mid + 1;
        }
        return l;
    }
    public int triangleNumber(int[] nums) {
        int count = 0;
        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 2; i++) {
            int k = i + 2;
            for (int j = i + 1; j < nums.length - 1 && nums[i] != 0; j++) {
                k = binarySearch(nums, k, nums.length - 1, nums[i] + nums[j]);
                count += k - j - 1;
            }
        }
        return count;
    }
}

Complexity Analysis

  • Time complexity : O(n^2 logn). In worst case inner loop will take nlogn (binary search applied n times).

  • Space complexity : O(logn). Sorting takes O(logn) space.


Approach #3 Linear Scan [Accepted]:

Algorithm

我们需要找到索引对 (i,j)的右临界值 k ,使得nums[i]+nums[j]>nums[k能够满足。 

为了找到 k 的右临界值,我们可以从 k=j+1 开始遍历,直到找到第一个 k 不满足上述不等式。那么在 [ j+1 ,k ) 范围内的元素一定会满足上述不等式,数量是 k - j - 1 .

Java

public class Solution {
    public int triangleNumber(int[] nums) {
        int count = 0;
        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 2; i++) {
            int k = i + 2;
            for (int j = i + 1; j < nums.length - 1 ; j++) {
                while (k < nums.length && nums[i] + nums[j] > nums[k])
                    k++;          //k最终值是:使得nums[i] + nums[j]<=nums[k]的最左索引
                count += k - j - 1;
            }
        }
        return count;
    }
}

Complexity Analysis

  • Time complexity : O(n^2). Loop of and will be executed O(n^2) times in total, because, we do not reinitialize the value of k for a new value of j chosen (for the same i). Thus the complexity will be O(n^2+n^2)=O(n^2).

  • Space complexity : O(logn). Sorting takes O(logn) space.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值