多邊形最大周長 Find Polygon With Largest Perimeter_Leetcode #2971

更新於 發佈於 閱讀時間約 5 分鐘

題目敘述

題目會給定我們輸入邊長陣列nums,請問我們從裡面能夠建構出來的多邊形的最大周長是多少

如果無解,返回-1


題目的原文敘述


約束條件

Constraints:

  • 3 <= n <= 10^5

輸入陣列長度nums介於3 ~ 十萬 之間。

  • 1 <= nums[i] <= 10^9

輸入陣列裡面每個元素值介於1 ~ 十億之間。


演算法 不等式 + MaxHeap

在三角形中,我們已經知道 任兩邊之和一定大於第三邊。

也可以說 比較小的邊長累積總和 > 最長的那一邊

image.png

image.png

其實推廣到 k邊形也是通用的。

在k邊形中,比較小的邊長累積總和 = S1 + S2 + ... + Sk-1 > Sk = 最長的那一邊。


怎麼證明呢?

幾何上可以用反證法這樣想,

如果Sk >= S1 + S2 + ... Sk-1

那剩下的那些邊長,就算緊緊地貼著Sk旁邊,也無法構成一個合法的多邊形。

因為Sk太長了,長到剩下的邊全部串在一起也碰不到Sk的另一端


有了這個思路和不等式之後,

我們就建造一個MaxHeap,每次從裡面挑一個當下最長的邊,檢查是否滿足剛剛提到的不等式:

在k邊形中,比較小的邊長累積總和 = S1 + S2 + ... + Sk-1 > Sk = 最長的那一邊。

如果可以,那麼當下的S1, S2, ... ,Sk 就構成一組合法的多邊形,

而且回傳周長S1+S2 + ... + Sk作為答案。


如果不行,就把Sk捨棄,下一輪再從MaxHeap 取出第二大的Sk-1,用同樣的不等式再檢查一次,反覆迭代,一直到最後剩下三個邊的時候,假如還是不行,那就代表無解,回傳-1。(因為三角形已經是邊數最小的多邊形了)


程式碼 不等式 + MaxHeap

class Solution:
def largestPerimeter(self, nums: List[int]) -> int:

# Assume we use all side length at first round
perimeter = sum(nums)
heapq._heapify_max(nums)

# Minimal number of sides of polygon is triangle, number of sides = 3
while len(nums) >= 3:

# Pick current max side length from Max Heap
# sk = max side length
Sk = heapq._heappop_max(nums)

# If Side 1 + Side 2 + ... + Side k-1 > max side length
# Then they can form a polygon with perimeter
if perimeter - Sk > Sk:
return perimeter

# If not, try next one
perimeter = perimeter - Sk
# =============================================
# If all fails, then there is No solution
return -1

複雜度分析 不等式 + MaxHeap

間複雜度: O( n log n)

建造MaxHeap花費O(n)

取最大邊長時,需要耗費O(log n)去動態調整MaxHeap,最多會有O(n)個回合,總共耗時O( n log n)。


空間複雜度: O(1)

MaxHeap 是 in-place建造,不耗用額外空間。

其他用到的都是固定尺寸的臨時變數,所需空間為O(1)常數級別。


關鍵知識點

在三角形中,我們已經知道 任兩邊之和一定大於第三邊。

也可以說 比較小的邊長累積總和 > 最長的那一邊


其實推廣到 k邊形也是通用的。

在k邊形中,比較小的邊長累積總和 = S1 + S2 + ... + Sk-1 > Sk = 最長的那一邊。


用不等式去找出最大多邊形的最長周長。


Reference:

[1] Find Polygon With the Largest Perimeter - LeetCode

留言
avatar-img
留言分享你的想法!
avatar-img
小松鼠的演算法樂園
95會員
427內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
2024/10/06
題目敘述 Rank Transform of an Array 給定一個陣列arr,請根據數字的大小給予序號,序號值介於1~len( set(arr) )之間。 最大的數字給予最大的序號。 次大的數字給予次大的序號。 ...依此類推 最小的數字給予最小的序號1。
Thumbnail
2024/10/06
題目敘述 Rank Transform of an Array 給定一個陣列arr,請根據數字的大小給予序號,序號值介於1~len( set(arr) )之間。 最大的數字給予最大的序號。 次大的數字給予次大的序號。 ...依此類推 最小的數字給予最小的序號1。
Thumbnail
2024/10/01
題目敘述 Check If Array Pairs Are Divisible by k 給定一個長度為偶數的整數陣列arr,和一個整數k 。 我們想把陣列元素兩兩一組組成pair,使得每個pair的總和可以被k整除。 如果做得到,返回True。 如果不行,返回False。
Thumbnail
2024/10/01
題目敘述 Check If Array Pairs Are Divisible by k 給定一個長度為偶數的整數陣列arr,和一個整數k 。 我們想把陣列元素兩兩一組組成pair,使得每個pair的總和可以被k整除。 如果做得到,返回True。 如果不行,返回False。
Thumbnail
2024/09/29
My Calendar II 給定一個行事曆的class定義和行程安排的介面。 請完成下列function 1.建構子MyCalendarTwo() 2.boolean book(int start, int end) 在行事曆加入一項新行程,起始時間為start, 結束時間為end。
Thumbnail
2024/09/29
My Calendar II 給定一個行事曆的class定義和行程安排的介面。 請完成下列function 1.建構子MyCalendarTwo() 2.boolean book(int start, int end) 在行事曆加入一項新行程,起始時間為start, 結束時間為end。
Thumbnail
看更多
你可能也想看
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
給定一個二維的二元矩陣,計算正方形的最大面積。利用DP演算法及最大化正方形邊長的方法,遍歷矩陣,釐清DP初始狀態並推導出DP狀態轉移關係式。複雜度分析說明了時間複雜度和空間複雜度。關鍵知識點是找出最大的正方形邊長。
Thumbnail
給定一個二維的二元矩陣,計算正方形的最大面積。利用DP演算法及最大化正方形邊長的方法,遍歷矩陣,釐清DP初始狀態並推導出DP狀態轉移關係式。複雜度分析說明了時間複雜度和空間複雜度。關鍵知識點是找出最大的正方形邊長。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定一個二元陣列nums(也就是說,陣列元素只有0,1這兩種情況)。 我們必須從裡面選擇一個元素刪除之後,請問連續為1的最長子陣列的長度是多少? 測試範例 Example 1: Input: nums = [1,1,0,1] Output: 3 Explanation:
Thumbnail
題目敘述 題目會給定一個二元陣列nums(也就是說,陣列元素只有0,1這兩種情況)。 我們必須從裡面選擇一個元素刪除之後,請問連續為1的最長子陣列的長度是多少? 測試範例 Example 1: Input: nums = [1,1,0,1] Output: 3 Explanation:
Thumbnail
題目敘述 題目會給定一個二元陣列nums(也就是說,陣列元素只有0,1這兩種情況)和指定的k值。 我們最多可以把k個0反轉成1,請問連續唯一的最長子陣列的長度是多少? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,1,1,0,0,0,1,1,1,1,
Thumbnail
題目敘述 題目會給定一個二元陣列nums(也就是說,陣列元素只有0,1這兩種情況)和指定的k值。 我們最多可以把k個0反轉成1,請問連續唯一的最長子陣列的長度是多少? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,1,1,0,0,0,1,1,1,1,
Thumbnail
題目敘述 題目會給定一個有n個整數的陣列nums和指定的k值,問我們長度為k的子陣列的平均值的最大值是多少? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,12,-5,-6,50,3], k = 4 Output: 12.75000 Explanati
Thumbnail
題目敘述 題目會給定一個有n個整數的陣列nums和指定的k值,問我們長度為k的子陣列的平均值的最大值是多少? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,12,-5,-6,50,3], k = 4 Output: 12.75000 Explanati
Thumbnail
題目敘述 題目會給兩個陣列nums1和nums2。 題目要求我們從中同步選擇長度為k的子序列,並且最大化子序列的分數, 回傳最高的分數值。 分數的定義: 分數 = (nums1[i0] + nums1[i1] +...+ nums1[ik - 1]) * min(nums2[i0] ,
Thumbnail
題目敘述 題目會給兩個陣列nums1和nums2。 題目要求我們從中同步選擇長度為k的子序列,並且最大化子序列的分數, 回傳最高的分數值。 分數的定義: 分數 = (nums1[i0] + nums1[i1] +...+ nums1[ik - 1]) * min(nums2[i0] ,
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News