欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Lintcode】382. Triangle Count

程序员文章站 2024-03-06 20:24:44
...

题目地址:

https://www.lintcode.com/problem/triangle-count/description

给定一个数组AA,可以从其中选出三个数形成三角形的三边长。问有多少种选法。

先将数组排序。这样A[i]A[i]A[j]A[j]A[k]A[k](其中i<j<ki<j<k)能组成三角形当且仅当A[i]+A[j]>A[k]A[i]+A[j]>A[k]。这样我们可以从k=2k=2开始枚举A[k]A[k],看一下A[0,...,k1]A[0,...,k-1]这一段里有多少个数对之和是大于A[k]A[k]的。这个可以用对撞双指针来做。

我们考虑数组B,怎样求有多少个数对的和大于给定数x呢。开两个指针lr分别初始化为l = 0r = B.length - 1。如果B[l] + B[r] > x,那么显然B[l, l + 1, l + 2, ..., r - 1]每个数都与B[r]的和是大于x的,一共是r - l个数,累加到结果中。此时右端点是B[r]的情况就全部枚举完了,所以让r--,继续枚举。反之,如果B[l] + B[r] <= x,那么显然B[r, r - 1, r - 2, ..., l]每个数都与B[l]的和都是小于等于x的,此时左端点是B[l]的情况就不用再考虑了,所以让l++,继续枚举。这样枚举的话,所有数对都被枚举到了(证明不难。对于任意数对下标(i,j)(i,j),我们根据最后双指针相遇的地点和区间[i,j][i,j]的关系分类讨论证明即可)。

代码如下:

import java.util.Arrays;

public class Solution {
    /**
     * @param S: A list of integers
     * @return: An integer
     */
    public int triangleCount(int[] S) {
        // write your code here
        // S长度不足则直接返回0
        if (S == null || S.length < 3) {
            return 0;
        }
        
        Arrays.sort(S);
        
        int res = 0;
        for (int i = 2; i < S.length; i++) {
            res += findLarger(S, i);
        }
        
        return res;
    }
    
    // 找一下S[0, ..., k - 1]中有多少个数对之和大于S[k]
    public int findLarger(int[] S, int k) {
        int i = 0, j = k - 1;
        
        int count = 0;
        while (i < j) {
            if (S[i] + S[j] > S[k]) {
                count += j - i;
                j--;
            } else {
                i++;
            }
        }
        
        return count;
    }
}

时间复杂度O(n2)O(n^2),空间O(1)O(1)