题目形容
这是 LeetCode 上的 1846. 减小和重新排列数组后的最大元素 ,难度为 中等。
Tag :「贪婪」
给你一个正整数数组 arr
。
请你对 arr
执行一些操作(也能够不进行任何操作),使得数组满足以下条件:
arr
中 第一个 元素必须为 $1$-
任意相邻两个元素的差的绝对值小于等于 $1$
对于任意的 $1 <= i < arr.length$,都满足
abs(arr[i]-arr[i-1])<=1
,abs(x)
为x
的绝对值。
你能够执行以下 $2$ 种操作任意次:
- 减小
arr
中任意元素的值,使其变为一个更小的正整数 - 重新排列
arr
中的元素,你能够以任意程序重新排列
请你返回执行以上操作后,在满足前文所述的条件下,arr
中可能的最大值。
示例 1:
输出:arr = [2,2,1,2,1]
输入:2
解释:咱们能够重新排列 arr 失去 [1,2,2,2,1],该数组满足所有条件。arr 中最大元素为 2。
示例 2:
输出:arr = [100,1,1000]
输入:3
解释:一个可行的计划如下:1. 重新排列 arr 失去 [1,100,1000]。2. 将第二个元素减小为 2。3. 将第三个元素减小为 3。当初 arr = [1,2,3],满足所有条件。arr 中最大元素为 3。
示例 3:
输出:arr = [1,2,3,4,5]
输入:5
解释:数组曾经满足所有条件,最大元素为 5。
提醒:
- $1 <= arr.length <= 10^5$
- $1 <= arr[i] <= 10^9$
根本剖析 & 证实
依据题意,数组的第一位必须是 $1$,且每个数只能 减小 或 不变,数值地位能够任意调整。
求解通过调整后,符合要求的数组中的最大值是多少。
首先符合条件的数组相邻位差值绝对值不超过 $1$,这限定了数组的必然是如下三种散布之一:
- (非严格)枯燥递加
- 存在波段
- (非严格)枯燥递增
证实一:获得最优解对应的数组「必然是」或者「可调整为」(非严格)枯燥递增的模式。
咱们应用反证法来证实另外两种散布不能获得最优解:
- (非严格)枯燥递加:题目限定了数的范畴为正整数,且第一位为 $1$,这种状况不必探讨了,跳过;
- 存在波段:咱们始终能够将波峰的右侧呈现的值,纳入到波峰的左侧,从而消掉这个波峰,最终将整个散布调整为「(非严格)枯燥递增」的模式,后果不会变差:
多个波段的状况也是同理,能够本人在纸上画画。
都是利用 波峰右侧的点能够调整成波峰左侧的点,从而使散布变为(非严格)枯燥递增。
至此,咱们证实了最优解对应的数组必然合乎(非严格)枯燥递增。
这启发咱们能够先对原数组排个序,在此基础上进行剖析。
对原数组排序失去的有序数组,不肯定是合乎「相邻位差值绝对值不超过 $1$」的,同时因为每个数值能够抉择 减小 或 不变。
证实二:当必须要对以后位进行调整的时,优先选择调整为「与前一值差值为 $1$ 的较大数」不会比调整为「与前一差值为 $0$ 的较小数」更差。
这能够应用归纳推理,假如采取「优先调整为与前一值差值为 $1$ 的较大数」失去的序列为 a
,采纳「优先调整与前一差值为 $0$ 的较小数」失去的序列为 b
。
依据「$a[0] = b[0] = 1$」、「a
和 b
长度统一」、「a
和 b
均为(非严格)枯燥递增」以及「a
和 b
均满足相邻位差值不超过 $1$」,可推导出 $sum(a) >= sum(b)$,和任意地位 $a[i] >= b[i]$,从而推导出 a
序列的最初一位必然大于等于 b
的最初一位。
即 b
不会比 a
更优。
证实三:调整大小的操作不会扭转数组元素之间的绝对地位关系。
在证实二的剖析中,咱们会对某些元素进行“减小”操作,使得整个数组最终满足「相邻位差值绝对值不超过 $1$」。
但该证实成立的还有一个很重要的前提条件,就是调整操作不会登程元素的地位重排。
那么该前提条件是否必然成立呢?答案是必然成立。
假如原排序数组中存在须要调整的点 $i$ 和点 $j$,且 $nums[i] <= nums[j]$。
为了让数组满足条件,它们都进行了“缩小”操作的调整,别离变为了 $p$ 和 $q$,如果触发地位重排的话,必然有 $nums[p] >= nums[q]$。
此时,咱们可能通过调整它们的变动关系:点 $i$ 变为点 $q$、点 $j$ 变成点 $p$ 来确保同样满足条件,且不触发元素在有序数组中的地位重排。
贪婪
排序,限定第一位值为 $1$,从前往后解决,依据每一位是否「必须批改(与上一位差值是否大于 $1$)」做决策,如果必须被批改,则批改为与前一值差值为 $1$ 的较大数。
代码:
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];
}
}
- 工夫复杂度:假设
Arrays.sort
应用的是双轴快排实现。复杂度为 $O(n\log{n})$ - 空间复杂度:假设
Arrays.sort
应用的是双轴快排实现。复杂度为 $O(\log{n})$
最初
这是咱们「刷穿 LeetCode」系列文章的第 No.1846
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,局部是有锁题,咱们将先把所有不带锁的题目刷完。
在这个系列文章外面,除了解说解题思路以外,还会尽可能给出最为简洁的代码。如果波及通解还会相应的代码模板。
为了不便各位同学可能电脑上进行调试和提交代码,我建设了相干的仓库:https://github.com/SharingSource/LogicStack-LeetCode。
在仓库地址里,你能够看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其余优选题解。
更多更全更热门的「口试 / 面试」相干材料可拜访排版精美的 合集新基地 🎉🎉
本文由 mdnice 多平台公布