乐趣区

关于后端:面试高频题值得仔细推敲的贪心及其证明

题目形容

这是 LeetCode 上的 1846. 减小和重新排列数组后的最大元素 ,难度为 中等

Tag :「贪婪」

给你一个正整数数组 arr

请你对 arr 执行一些操作(也能够不进行任何操作),使得数组满足以下条件:

  1. arr 中 第一个 元素必须为 $1$
  2. 任意相邻两个元素的差的绝对值小于等于 $1$

    对于任意的 $1 <= i < arr.length$,都满足 abs(arr[i]-arr[i-1])<=1abs(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$」、「ab 长度统一」、「ab 均为(非严格)枯燥递增」以及「ab 均满足相邻位差值不超过 $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 多平台公布

退出移动版