leetcode
leetcode 2701 ~ 2750
找到最大周长的多边形

找到最大周长的多边形

难度:

标签:

题目描述

You are given an array of positive integers nums of length n.

A polygon is a closed plane figure that has at least 3 sides. The longest side of a polygon is smaller than the sum of its other sides.

Conversely, if you have k (k >= 3) positive real numbers a1, a2, a3, ..., ak where a1 <= a2 <= a3 <= ... <= ak and a1 + a2 + a3 + ... + ak-1 > ak, then there always exists a polygon with k sides whose lengths are a1, a2, a3, ..., ak.

The perimeter of a polygon is the sum of lengths of its sides.

Return the largest possible perimeter of a polygon whose sides can be formed from nums, or -1 if it is not possible to create a polygon.

 

Example 1:

Input: nums = [5,5,5]
Output: 15
Explanation: The only possible polygon that can be made from nums has 3 sides: 5, 5, and 5. The perimeter is 5 + 5 + 5 = 15.

Example 2:

Input: nums = [1,12,1,2,5,50,3]
Output: 12
Explanation: The polygon with the largest perimeter which can be made from nums has 5 sides: 1, 1, 2, 3, and 5. The perimeter is 1 + 1 + 2 + 3 + 5 = 12.
We cannot have a polygon with either 12 or 50 as the longest side because it is not possible to include 2 or more smaller sides that have a greater sum than either of them.
It can be shown that the largest possible perimeter is 12.

Example 3:

Input: nums = [5,5,50]
Output: -1
Explanation: There is no possible way to form a polygon from nums, as a polygon has at least 3 sides and 50 > 5 + 5.

 

Constraints:

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

代码结果

运行时间: 68 ms, 内存: 29.9 MB


/*
题目思路:
1. 对数组进行排序。
2. 从最大的元素开始,检查前两个元素之和是否大于当前元素。
3. 如果条件满足,返回三个元素的和。
4. 如果不满足,继续向前检查。
5. 如果遍历完数组,找不到满足条件的三条边,返回-1。
*/
import java.util.Arrays;
public class Solution {
    public int largestPerimeter(int[] nums) {
        Arrays.sort(nums); // Step 1: 对数组进行排序
        return IntStream.range(2, nums.length) // Step 2: 从最大的元素开始
                        .map(i -> nums.length - 1 - i)
                        .filter(i -> nums[i] < nums[i + 1] + nums[i + 2]) // Step 3: 检查前两个元素之和是否大于当前元素
                        .map(i -> nums[i] + nums[i + 1] + nums[i + 2]) // Step 4: 条件满足,返回三个元素的和
                        .findFirst()
                        .orElse(-1); // Step 5: 遍历完数组,找不到满足条件的三条边,返回-1
    }
}

解释

方法:

此题解的基本思路是首先对数组进行排序,然后从最大的元素开始,检查能否与前面的元素形成多边形。具体步骤包括:1. 计算数组的总和 `s`。2. 对数组进行排序。3. 从数组的最后一个元素开始向前遍历,检查当前元素是否小于前面所有元素的和(即是否可以与前面的元素形成多边形)。如果可以,则返回当前的总和 `s` 作为最大周长;如果不可以,就从总和中减去当前元素,继续检查前一个元素。4. 如果遍历完所有元素后都不能形成多边形,则返回 -1。

时间复杂度:

O(n log n)

空间复杂度:

O(1)

代码细节讲解

🦆
在题解中,为什么首先需要对数组进行排序?这个步骤对算法的正确性和效率有什么影响?
排序是为了简化多边形的验证过程。通过将数组排序,可以确保在从数组的最大元素向前检查时,能够更方便地验证最大元素是否小于其余元素之和。这种方法有助于快速确定最大元素是否能与前面的元素组成多边形,而不需要对每个组合进行单独的验证。排序还有助于提高算法效率,因为一旦找到符合条件的组合,就可以立即停止搜索,而不需要继续检查更小的组合。
🦆
题解中提到`从最大的元素开始检查能否与前面的元素形成多边形`,这种方法是否保证了找到的多边形一定有最大的周长?
是的,这种方法确保了找到的多边形具有最大的周长。因为数组经过排序后,我们是从最大的元素开始向前查找,这样可以首先尝试将最大的元素包含在内。由于多边形的周长是边长的总和,包括尽可能大的边将有助于确保总和最大。一旦找到符合多边形条件的组合,由于是从最大值开始,所以这个组合的周长必定是最大可能的周长。
🦆
在判断`nums[i] * 2 < s`时,为什么使用这个条件来确定是否可以形成多边形?
这个条件用于验证选定的最大边(nums[i])是否小于其余所有边的总和。按照多边形的形成规则,任何一边的长度必须小于其他所有边长度的总和,以确保这些边可以闭合成一个多边形。在题解中,`s`代表当前考虑的所有边的总长度,`nums[i]`是当前考虑的最大边。如果`nums[i] * 2 < s`成立,意味着`nums[i]`小于其余边的总和,因此可以与它们形成一个闭合的多边形,从而满足多边形的基本形成条件。

相关问题