LeetCode 2111. 使数组 K 递增的最少操作次数
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 2111. 使数组 K 递增的最少操作次数相关的知识,希望对你有一定的参考价值。
文章目录
一、题目
1、题目描述
给你一个下标从 0 0 0 开始包含 n n n 个正整数的数组
arr
,和一个正整数k
。如果对于每个满足k <= i <= n-1
的下标 i i i ,都有arr[i-k] <= arr[i]
,那么我们称arr
是k
递增 的。
每一次操作中,你可以选择一个下标 i i i 并将arr[i]
改成任意正整数。请你返回对于给定的k
,使数组变成k
递增的最少操作次数 。
样例输入:arr = [5,4,3,2,1], k = 1
样例输出:4
2、基础框架
- C语言 给出的基础框架代码如下:
int kIncreasing(int* arr, int arrSize, int k)
3、原题链接
二、解题报告
1、思路分析
(
1
)
(1)
(1) 如果
k
=
1
k = 1
k=1,我们是不是就是单纯的求这个数组,把它任意数改成完以后,能够得到的递增序列的最少操作数。
(
2
)
(2)
(2) 如果
k
>
1
k > 1
k>1,其实就是分别求
k
k
k 个序列的最少操作数。
(
3
)
(3)
(3) 所以,只需要考虑
k
=
1
k=1
k=1 的情况,对于
k
>
1
k>1
k>1 的情况,其实就是调用同一个函数求解即可。
(
4
)
(4)
(4) 对一个长度为
n
n
n 的序列,求出它的最长单调不降子序列,长度为
l
l
l,则最少操作数就是两者的差值
n
−
l
n-l
n−l。
(
5
)
(5)
(5) 累加所有的差值就是最后的答案。
(
6
)
(6)
(6) 由于数据量的限制,所以 最长单调不降子序列 只能采用
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) 的算法,令 g[i]
表示长度为 i
的最长单调不降子序列的最后一个元素的值,那么它一定是越小越好(这是一个贪心的思想)。
(
7
)
(7)
(7) 我们来仔细思考一下这个贪心思想,对于两个长度都为 4 的 最长单调不降子序列 来说,如图所示:
保留[0, 1, 3, 5]
一定会比[1, 4, 7, 9]
更优,为什么呢?比如我们来了一个 7
,它能够接到 5
后面,使得我的序列变长;但是,却不能接到9
的后面。所以[1, 4, 7, 9]
可以舍去。
(
8
)
(8)
(8) 那么,我们真的要保留[0, 1, 3, 5]
吗?答案是否定的。因为对于一个序列它一定是单调不降的,而进行状态转移的时候只需要考虑最后一个元素,所以我们只需要保存最后一个元素,也就是对于长度为 4
的情况,我们只需要保留 5
就可以了。这就是上文提到的 g[4]
。
(
9
)
(9)
(9) 对于所有的
i
i
i,我们都把
g
[
i
]
g[i]
g[i] 求出来,这样是不是就可以把最大的长度给求出来啦。
(
10
)
(10)
(10)
g
[
i
]
g[i]
g[i] 这个数组这么定义有什么好处呢?好处就是它是一个单调不降的序列,我们可以对它进行二分查找以及插入。也就是可以通过 O(logn) 的时间复杂度快速更新
g
[
i
]
g[i]
g[i] 的值。
(
11
)
(11)
(11) 对于每个元素
v
=
a
[
i
]
v = a[i]
v=a[i],我们需要去
g
[
]
g[\\ ]
g[ ] 数组里面,找到一个位置
x
x
x,满足
v
<
g
[
x
]
v \\lt g[x]
v<g[x],并且
x
x
x 要尽量的小。由于
g
[
]
g[\\ ]
g[ ] 是单调不降的,所以可以利用二分查找。
(
12
)
(12)
(12) 如果对最长单调子序列还不是很明白,可以参考我的专栏:夜深人静写算法(二十)- 最长单调子序列。
2、时间复杂度
最坏时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn) 。
3、代码详解
int g[100005]; // g[i] 表示长度为 i 的最长单调不降子序列的最后一个元素的值
int maxLongestNonDescendingSeq(int *a, int size)
int gsize = 0;
int i, x, v;
int l, r, mid;
for(i = 0; i < size; ++i)
v = a[i];
x = -1;
l = 0;
r = gsize - 1;
while(l <= r)
mid = (l + r) >> 1;
if(v < g[mid])
x = mid;
r = mid - 1;
else
l = mid + 1;
if(x == -1)
g[gsize++] = v;
else
g[x] = v;
return gsize;
int kIncreasing(int* arr, int arrSize, int k)
int i, j;
int ans = 0;
int tmp[100005], tmpSize;
for(i = 0; i < k; ++i)
tmpSize = 0;
for(j = i; j < arrSize; j += k)
tmp[tmpSize++] = arr[j];
ans += tmpSize - maxLongestNonDescendingSeq(tmp, tmpSize);
return ans;
三、本题小知识
思考:如果要求严格递增的话要怎么做呢?
四、加群须知
相信看我文章的大多数都是「 大学生 」,能上大学的都是「 精英 」,那么我们自然要「 精益求精 」,如果你还是「 大一 」,那么太好了,你拥有大把时间,当然你可以选择「 刷剧 」,然而,「 学好算法 」,三年后的你自然「 不能同日而语 」。
那么这里,我整理了「 几十个基础算法 」 的分类,点击开启:
如果链接被屏蔽,或者有权限问题,可以私聊作者解决。
大致题集一览:
为了让这件事情变得有趣,以及「 照顾初学者 」,目前题目只开放最简单的算法 「 枚举系列 」 (包括:线性枚举、双指针、前缀和、二分枚举、三分枚举),当有 一半成员刷完 「 枚举系列 」 的所有题以后,会开放下个章节,等这套题全部刷完,你还在群里,那么你就会成为「 夜深人静写算法 」专家团 的一员。
不要小看这个专家团,三年之后,你将会是别人 望尘莫及 的存在。如果要加入,可以联系我,考虑到大家都是学生, 没有「 主要经济来源 」,在你成为神的路上,「 不会索取任何 」。
🔥联系作者,或者扫作者主页二维码加群,加入刷题行列吧🔥
🔥让天下没有难学的算法🔥
C语言免费动漫教程,和我一起打卡! 🌞《光天化日学C语言》🌞
让你养成九天持续刷题的习惯 🔥《九日集训》🔥
入门级C语言真题汇总 🧡《C语言入门100例》🧡
组团学习,抱团生长 🌌《算法零基础100讲》🌌
几张动图学会一种数据结构 🌳《画解数据结构》🌳
竞赛选手金典图文教程 💜《夜深人静写算法》💜
以上是关于LeetCode 2111. 使数组 K 递增的最少操作次数的主要内容,如果未能解决你的问题,请参考以下文章