跳转至

2971. 找到最大周长的多边形

题目描述

给你一个长度为 n 的  整数数组 nums 。

多边形 指的是一个至少有 3 条边的封闭二维图形。多边形的 最长边 一定 小于 所有其他边长度之和。

如果你有 k (k >= 3)个  数 a1a2a3, ...,ak 满足 a1 <= a2 <= a3 <= ... <= ak a1 + a2 + a3 + ... + ak-1 > ak ,那么 一定 存在一个 k 条边的多边形,每条边的长度分别为 a1 ,a2 ,a3 , ...,ak 。

一个多边形的 周长 指的是它所有边之和。

请你返回从 nums 中可以构造的 多边形 最大周长 。如果不能构造出任何多边形,请你返回 -1 。

 

示例 1:

输入:nums = [5,5,5]
输出:15
解释:nums 中唯一可以构造的多边形为三角形,每条边的长度分别为 5 ,5 和 5 ,周长为 5 + 5 + 5 = 15 。

示例 2:

输入:nums = [1,12,1,2,5,50,3]
输出:12
解释:最大周长多边形为五边形,每条边的长度分别为 1 ,1 ,2 ,3 和 5 ,周长为 1 + 1 + 2 + 3 + 5 = 12 。
我们无法构造一个包含变长为 12 或者 50 的多边形,因为其他边之和没法大于两者中的任何一个。
所以最大周长为 12 。

示例 3:

输入:nums = [5,5,50]
输出:-1
解释:无法构造任何多边形,因为多边形至少要有 3 条边且 50 > 5 + 5 。

 

提示:

  • 3 <= n <= 105
  • 1 <= nums[i] <= 109

解法

方法一:排序 + 前缀和

我们可以将数组 $nums$ 排序,然后定义一个答案变量 $ans$,初始值为 $-1$。

接下来,我们在 $[3, n]$ 的范围内枚举最长边 $a_k$,如果 $a_1 + a_2 + \cdots + a_{k-1} > a_k$,那么就可以构成一个周长为 $a_1 + a_2 + \cdots + a_k$ 的多边形。这里,我们可以使用前缀和数组 $s$,其中 $s_i = a_1 + a_2 + \cdots + a_i$,那么 $a_1 + a_2 + \cdots + a_{k-1} = s_{k-1}$,判断是否 $s_{k-1} > a_k$,如果是,那么更新答案 $ans = \max(ans, s_k)$。

时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 $nums$ 的长度。

1
2
3
4
5
6
7
8
9
class Solution:
    def largestPerimeter(self, nums: List[int]) -> int:
        nums.sort()
        s = list(accumulate(nums, initial=0))
        ans = -1
        for k in range(3, len(nums) + 1):
            if s[k - 1] > nums[k - 1]:
                ans = max(ans, s[k])
        return ans
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Solution {
    public long largestPerimeter(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        long[] s = new long[n + 1];
        for (int i = 1; i <= n; ++i) {
            s[i] = s[i - 1] + nums[i - 1];
        }
        long ans = -1;
        for (int k = 3; k <= n; ++k) {
            if (s[k - 1] > nums[k - 1]) {
                ans = Math.max(ans, s[k]);
            }
        }
        return ans;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Solution {
public:
    long long largestPerimeter(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int n = nums.size();
        vector<long long> s(n + 1);
        for (int i = 1; i <= n; ++i) {
            s[i] = s[i - 1] + nums[i - 1];
        }
        long long ans = -1;
        for (int k = 3; k <= n; ++k) {
            if (s[k - 1] > nums[k - 1]) {
                ans = max(ans, s[k]);
            }
        }
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func largestPerimeter(nums []int) int64 {
    sort.Ints(nums)
    n := len(nums)
    s := make([]int, n+1)
    for i, x := range nums {
        s[i+1] = s[i] + x
    }
    ans := -1
    for k := 3; k <= n; k++ {
        if s[k-1] > nums[k-1] {
            ans = max(ans, s[k])
        }
    }
    return int64(ans)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
function largestPerimeter(nums: number[]): number {
    nums.sort((a, b) => a - b);
    const n = nums.length;
    const s: number[] = Array(n + 1).fill(0);
    for (let i = 0; i < n; ++i) {
        s[i + 1] = s[i] + nums[i];
    }
    let ans = -1;
    for (let k = 3; k <= n; ++k) {
        if (s[k - 1] > nums[k - 1]) {
            ans = Math.max(ans, s[k]);
        }
    }
    return ans;
}

评论