使数组不递减的最小操作数
Posted
技术标签:
【中文标题】使数组不递减的最小操作数【英文标题】:Minimum number of operations to make an array non-decreasing 【发布时间】:2021-12-20 01:18:42 【问题描述】:你有一个整数数组。
在一个步骤中,您可以将索引处的值更改为任何整数值。 使数组不递减的最少步数是多少?
例如1:
如果数组是[8,12,11,15],
我们可以将索引 2 处的值从 11 更改为 13。然后数组 变为 [8, 12, 13, 15]
所以,不需要步骤 = 1
例如 2:
如果数组是[9, 2, 5, 18, 20, 25, 19],
我们可以将索引 0 处的值从 9 更改为 2,将索引 6 处的值从 19 更改为 30。然后数组 变为 [2, 2, 5, 18, 20, 25, 30]
所以,不需要步骤 = 2
例如 3:
如果数组是[9,11,5,7],
我们可以将索引 2 处的值从 5 更改为 11,将索引 3 处的值从 7 更改为 11。然后数组 变为 [9, 11, 11, 11]
所以,不需要步骤 = 2
例如 4:
如果数组是[13, 12, 10, 7, 6],
进行更改后,数组变为 [13, 13, 13, 13, 13] 或 [6, 7, 10, 12, 13]。有多种方法可以做到这一点。
所以,不需要步骤 = 4
我尝试的一种方法是找到所有递减子序列并将它们的长度 -1 添加到名为 ans
的变量中。然后返回它。但它在上面提到的 Eg 3 中失败了。
如何解决?
【问题讨论】:
您是否尝试过将其建模为图形,然后在其上使用 BFS?对于每个将值放大到之前的值或将值减小到之后的值的操作,您都会有边。 你能发布原始问题链接吗?所以我们可以测试我们的解决方案。 @Ch3steR 抱歉,我没有链接。我的一个朋友问我,他现在没有回应。试了一会儿,写了代码,有些测试用例自相矛盾,我这里提了。 @UlrichEckhardt 不,我没试过。但这真的需要吗?我的意思是,这不能以更简单的方式完成,只涉及数组的遍历吗? 不知道是否需要。根据我的经验,使用基于图形的方法来考虑这一点是一个好的开始。也许这样做,您会注意到导致更简单解决方案的模式?无论如何,将其视为图形并不意味着您必须在代码中创建图形。通常,尤其是使用 BFS,您可以从队列中的初始值开始,然后在队列弹出时将新的中间值添加到队列中,因此图只是隐含的。这可能需要额外的思考,例如所以你不会陷入循环,但它可以工作。 【参考方案1】:我觉得这个问题相当于找到序列中最长的非递减链。
取每个索引 i 作为图的节点。那么节点 i 有一个指向节点 j 的箭头当且仅当 i
由于条件 i
【讨论】:
【参考方案2】:正如@sfx 提到的,这相当于找到最长的非递减子序列。
如果在输入数组A中找到任何非递减子序列S,则只需A中剩余元素的值更改为使整个数组不递减。要改变的元素个数是|A| - |S|。
如果该子序列是最长非递减子序列,它为您提供了已排序的最大元素数量,那么要更改的元素数量,|A| - |S|,将被最小化。如果您选择了任何较短的非递减子序列,则需要更改更多元素。
您可以使用Patience sorting 查找此子序列的长度。
来自***的算法:
-
发的第一张牌形成一个由单张牌组成的新牌堆。
随后的每张牌都放在某个现有牌堆上,其顶牌的值不低于新牌的值,或者放在所有现有牌堆的右侧,从而形成一个新牌堆。
当没有剩余牌可发时,游戏结束。
使用您的示例 3:
[9, 11, 5, 7]
插入 [9]:
[9]
插入[11]:输出数组中没有大于等于[11]的值,所以再添加一个栈:
[9, 11]
插入[5]:第一个大于等于[5]的值为[9],所以替换[9]:
[5, 11]
插入[7]:第一个大于等于[7]的值为[11],替换[11]:
[5, 7]
输出数组的长度是最长的非递减子序列的长度。使整个序列不递减的操作次数等于输入数组的元素个数减去这个子序列的长度。
使用二分查找来确定下一个值的放置位置,这种方法的最坏情况时间复杂度为O(n log n)。
您可以在此处找到关于耐心排序在查找最长递增子序列中的正确性的讨论和参考: Why does Patience sorting find the longest increasing subsequence?
【讨论】:
以上是关于使数组不递减的最小操作数的主要内容,如果未能解决你的问题,请参考以下文章