本文正在參加「Python主題月」,詳情查看 活動連接html
這是 LeetCode 上的 1846. 減少和從新排列數組後的最大元素 ,難度爲 中等。git
Tag : 「貪心」github
給你一個正整數數組 arr 。請你對 arr 執行一些操做(也能夠不進行任何操做),使得數組知足如下條件:數組
你能夠執行如下 2 種操做任意次:markdown
請你返回執行以上操做後,在知足前文所述的條件下,arr 中可能的 最大值 。app
示例 1:oop
輸入:arr = [2,2,1,2,1]
輸出:2
解釋:
咱們能夠從新排列 arr 獲得 [1,2,2,2,1] ,該數組知足全部條件。
arr 中最大元素爲 2 。
複製代碼
示例 2:post
輸入:arr = [100,1,1000]
輸出:3
解釋:
一個可行的方案以下:
1. 從新排列 arr 獲得 [1,100,1000] 。
2. 將第二個元素減少爲 2 。
3. 將第三個元素減少爲 3 。
如今 arr = [1,2,3] ,知足全部條件。
arr 中最大元素爲 3 。
複製代碼
示例 3:ui
輸入:arr = [1,2,3,4,5]
輸出:5
解釋:數組已經知足全部條件,最大元素爲 5 。
複製代碼
提示:spa
1 <= arr[i] <=
根據題意,數組的第一位必須是 ,且每一個數只能 減少 或 不變,數值位置能夠任意調整。
求解通過調整後,符合要求的數組中的最大值是多少。
首先符合條件的數組相鄰位差值絕對值不超過 ,這限定了數組的必然是以下三種分佈之一:
證實一:取得最優解對應的數組「必然是」或者「可調整爲」(非嚴格)單調遞增的形式。
咱們使用反證法來證實另外兩種分佈不能取得最優解:
多個波段的狀況也是同理,能夠本身在紙上畫畫。
都是利用 波峯右側的點能夠調整成波峯左側的點,從而使分佈變爲(非嚴格)單調遞增。
至此,咱們證實了最優解對應的數組必然符合(非嚴格)單調遞增。
這啓發咱們能夠先對原數組排個序,在此基礎上進行分析。
對原數組排序獲得的有序數組,不必定是符合「相鄰位差值絕對值不超過 」的,同時因爲每一個數值能夠選擇 減少 或 不變。
證實二:當必需要對當前位進行調整的時,優先選擇調整爲「與前一值差值爲 的較大數」不會比調整爲「與前一差值爲 的較小數」更差。
這可使用概括推理,假設採起「優先調整爲與前一值差值爲
的較大數」獲得的序列爲 a
,採用「優先調整與前一差值爲
的較小數」獲得的序列爲 b
。
根據「
」、「a
和 b
長度一致」、「a
和 b
均爲(非嚴格)單調遞增」以及「a
和 b
均知足相鄰位差值不超過
」,可推導出
,和任意位置
,從而推導出 a
序列的最後一位必然大於等於 b
的最後一位。
即 b
不會比 a
更優。
證實三:調整大小的操做不會改變數組元素之間的相對位置關係。
在證實二的分析中,咱們會對某些元素進行「減少」操做,使得整個數組最終知足「相鄰位差值絕對值不超過 」。
但該證實成立的還有一個很重要的前提條件,就是調整操做不會出發元素的位置重排。
那麼該前提條件是否必然成立呢?答案是必然成立。
假設原排序數組中存在須要調整的點 和點 ,且 。
爲了讓數組知足條件,它們都進行了「減小」操做的調整,分別變爲了 和 ,若是觸發位置重排的話,必然有 。
此時,咱們可以經過調整它們的變化關係:點 變爲點 、點 變成點 來確保一樣知足條件,且不觸發元素在有序數組中的位置重排。
排序,限定第一位值爲 ,從前日後處理,根據每一位是否「必須修改(與上一位差值是否大於 )」作決策,若是必須被修改,則修改成與前一值差值爲 的較大數。
Java 代碼:
class Solution {
public int maximumElementAfterDecrementingAndRearranging(int[] arr) {
int n = arr.length;
Arrays.sort(arr);
arr[0] = 1;
for (int i = 1; i < n; i++) {
if (arr[i] - arr[i - 1] > 1) {
arr[i] = arr[i - 1] + 1;
}
}
return arr[n - 1];
}
}
複製代碼
Python 3 代碼:
class Solution:
def maximumElementAfterDecrementingAndRearranging(self, arr: List[int]) -> int:
n = len(arr)
arr.sort()
arr[0] = 1
for i in range(1, n):
if arr[i] - arr[i - 1] > 1:
arr[i] = arr[i - 1] + 1
return arr[n - 1]
複製代碼
Arrays.sort
使用的是雙軸快排實現。複雜度爲
Arrays.sort
使用的是雙軸快排實現。複雜度爲
這是咱們「刷穿 LeetCode」系列文章的第 No.1846
篇,系列開始於 2021/01/01,截止於起始日 LeetCode 上共有 1916 道題目,部分是有鎖題,咱們將先把全部不帶鎖的題目刷完。
在這個系列文章裏面,除了講解解題思路之外,還會盡量給出最爲簡潔的代碼。若是涉及通解還會相應的代碼模板。
爲了方便各位同窗可以電腦上進行調試和提交代碼,我創建了相關的倉庫:github.com/SharingSour… 。
在倉庫地址裏,你能夠看到系列文章的題解連接、系列文章的相應代碼、LeetCode 原題連接和其餘優選題解。