最大化未出现自然数问题 | 豆包MarsCode AI刷题
问题描述
小F手中有一个包含n个自然数的集合(集合中的数字可能会重复出现)。他可以对集合中的数字进行若干次操作,每次操作可以选择集合中的一个数字x,并将其替换为一个大于x的数字y。小F的目标是通过这些操作,使得集合中最大的未出现的自然数K尽可能大。你的任务是计算出这个最大的K值。
测试样例
样例1:
输入:
n = 5, a = [5, 0, 0, 2, 2]输出:4
样例2:
输入:
n = 6, a = [1, 0, 3, 4, 4, 5]输出:2
样例3:
输入:
n = 4, a = [0, 1, 2, 3]输出:4
样例4:
输入:
n = 7, a = [7, 6, 5, 4, 3, 2, 1]输出:0
样例5:
输入:
n = 5, a = [0, 1, 2, 1, 3]输出:5
示例解析
-
输入:
n = 5, a = [5, 0, 0, 2, 2]- 排序后:
a = [0, 0, 2, 2, 5] - 从 0 开始逐步覆盖:0 -> 1 -> 2 -> 3 -> 4。返回
4。
- 排序后:
-
输入:
n = 6, a = [1, 0, 3, 4, 4, 5]- 排序后:
a = [0, 1, 3, 4, 4, 5] - 从 0 开始逐步覆盖:0 -> 1 -> 2。返回
2。
- 排序后:
-
输入:
n = 4, a = [0, 1, 2, 3]- 排序后:
a = [0, 1, 2, 3] - 从 0 开始逐步覆盖:0 -> 1 -> 2 -> 3 -> 4。返回
4。
- 排序后:
题解思路
这道题目的目标是通过一系列操作,找到一个最大值 K,使得 K 是集合中最大的未出现的自然数。每次操作可以选择集合中的一个数字 x,并将其替换为一个大于 x 的数字 y。换句话说,操作的本质是可以增加集合中的数字,但不允许减少任何数字。我们的目标是尽量让集合中的自然数覆盖从 0 到 K-1 的所有自然数,从而使得 K 最大。
我们可以采用一个贪心算法来解决这个问题,步骤如下:
- 排序:首先对数组进行排序。因为我们希望逐步填补从 0 到 K-1 的自然数,排序后的数组使我们能够从最小的数字开始处理,方便找到当前能覆盖的最小自然数。
- 遍历并替换:遍历排序后的数组,尝试用当前元素来覆盖一个“未出现的”自然数。如果当前元素小于等于目标自然数(即“未出现的自然数”),则我们可以将其用来覆盖这个数字,同时更新目标自然数。
- 终止条件:如果当前元素大于目标自然数,那么说明我们无法用当前的数字来覆盖目标自然数,算法结束。此时,目标自然数即为集合中最大的未出现的自然数。
详细步骤
- 排序:先对数组进行升序排序,方便我们从小到大地填充自然数。
- 贪心选择:遍历数组中的每一个数字,尝试将其替换成目标自然数。如果当前数字小于目标自然数,那么我们就可以认为目标自然数已经被覆盖,目标自然数加 1。
- 判断:如果当前数字大于目标自然数,那么我们无法用这个数字覆盖目标自然数,说明目标自然数就是当前数组中最大的未出现的自然数。
代码实现
import java.util.*;
public class Main {
public static int solution(int n, int[] a) {
// 对集合进行排序
Arrays.sort(a);
int target = 0; // 当前目标自然数,初始化为0
// 遍历排序后的数组
for (int i = 0; i < n; i++) {
// 如果当前元素大于等于目标自然数,则我们可以将它替换为目标自然数
if (a[i] >= target) {
target++; // 覆盖目标自然数,目标自然数加1
}
}
// 最终的target即为集合中最大的未出现自然数
return target;
}
public static void main(String[] args) {
// 测试用例
System.out.println(solution(5, new int[]{5, 0, 0, 2, 2}) == 4);
System.out.println(solution(6, new int[]{1, 0, 3, 4, 4, 5}) == 2);
System.out.println(solution(4, new int[]{0, 1, 2, 3}) == 4);
System.out.println(solution(7, new int[]{7, 6, 5, 4, 3, 2, 1}) == 0);
System.out.println(solution(5, new int[]{0, 1, 2, 1, 3}) == 5);
}
}
解释
-
排序:首先对数组进行排序,确保我们能从小到大地处理数字。例如,
[5, 0, 0, 2, 2]排序后为[0, 0, 2, 2, 5],这样我们可以逐步覆盖从 0 开始的自然数。 -
贪心策略:我们用一个变量
target来表示当前我们希望覆盖的自然数。初始时target = 0。遍历排序后的数组,遇到的每个数字:- 如果当前数字大于等于
target,我们可以将其替换为target,然后让target增加 1,表示我们成功覆盖了一个自然数。 - 如果当前数字小于
target,我们跳过它,因为它无法帮助我们覆盖新的自然数。
- 如果当前数字大于等于
-
返回值:当数组遍历完成后,
target就是当前未出现的最大自然数。
总结
这道题通过贪心算法,从最小的自然数开始尝试逐步覆盖。排序使得我们可以有效地从小到大地填补自然数,最终求得最大的未出现自然数。