俄罗斯方块
思路分析
- 读取输入数据:
- 15×10的游戏网格
- 4×4的板块形状
- 起始列号
- 处理板块:
- 提取板块中所有方块的位置
- 根据起始列号计算板块在网格中的水平位置
- 模拟下落过程:
- 从顶部开始尝试下落
- 检查是否能继续下落(不超出边界且不与其他方块重叠)
- 找到最终的落点位置
- 更新网格:
- 将板块的方块添加到网格中
动画演示: 重点看几个变量的变化
详细的内容在代码的中都有讲解了:
参考代码
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取15*10的游戏网格
int[][] gameBoard = new int[20][20];
for (int i = 1; i <= 15; i++) {
for (int j = 1; j <= 10; j++) {
gameBoard[i][j] = scanner.nextInt();
}
}
// 读取4*4的板块形状
int[][] pattern = new int[5][5];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
pattern[i][j] = scanner.nextInt();
}
}
// 读取起始劣号(1-7)
int startCol = scanner.nextInt();
// 提取板块中所有方块的位置
List<int[]> blocks = new ArrayList<>();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (pattern[i][j] == 1) {
blocks.add(new int[]{i, j});
}
}
}
// 计算板块在网格中的起始列
int y = startCol;
// 起始行
int x = 1; // 从顶部开始
// 尝试下落到下一行, 看看能不能移动
while (canMoveTo(x + 1, y, blocks, gameBoard)) {
// 可以继续下落
x++;
}
// 将板块添加到网格中
for (int[] block : blocks) {
// 这个是在板块中的位置
int patternX = block[0];
int patternY = block[1];
// 加上基础的位置, 就是在网格中的位置
int gridX = x + patternX;
int gridY = y + patternY;
gameBoard[gridX][gridY] = 1;
}
// 输出结果
for (int i = 1; i <= 15; i++) {
for (int j = 1; j <= 10; j++) {
System.out.print(gameBoard[i][j] + " ");
}
System.out.println();
}
}
private static boolean canMoveTo(int x, int y, List<int[]> blocks, int[][] gameBoard) {
for (int[] block : blocks) {
// 这个是在板块中的位置
int patternX = block[0];
int patternY = block[1];
// 加上基础的位置, 就是在网格中的位置
int gridX = x + patternX;
int gridY = y + patternY;
// 检查是否超出底部, 或者网格中的这个位置已经有方块了
if (gridX > 15 || gameBoard[gridX][gridY] == 1) {
return false;
}
}
// 可以继续下落
return true;
}
}
窗户
思路步骤:
- 读取 N 和 M
- 初始化窗口列表 windows(按输入顺序添加,先输入的为底层)
- 对于每次点击 (x, y):
- 如果 (x, y) 不在任何窗口中:
- 输出 "IGNORED"
- 如果 (x, y) 在某个窗口中:
- 将该窗口移动到最上方
- 输出该窗口的编号
- 如果 (x, y) 不在任何窗口中:
数组实现
import java.util.Scanner;
public class Main {
static class Window {
int id;
int x1, x2, y1, y2;
public Window(int id, int x1, int x2, int y1, int y2) {
this.id = id;
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
}
}
static int n, m;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Window[] windows = new Window[15];
n = scanner.nextInt();
m = scanner.nextInt();
for (int i = 1; i <= n; i++) {
int x1 = scanner.nextInt();
int y1 = scanner.nextInt();
int x2 = scanner.nextInt();
int y2 = scanner.nextInt();
windows[i] = new Window(i, x1, x2, y1, y2);
}
while (m-- > 0) {
int x = scanner.nextInt();
int y = scanner.nextInt();
// 找到点击到的窗口
int index = findWindow(x, y, windows);
if (index == 0) {
// 没有点击到窗口
System.out.println("IGNORED");
continue;
}
Window window = windows[index];
// 找到了窗口
System.out.println(window.id);
// 将窗口放到最上方
for (int i = index; i < n; i++) {
windows[i] = windows[i + 1];
}
windows[n] = window;
}
}
private static int findWindow(int x, int y, Window[] windows) {
int index = 0;
for (int i = n; i >= 1; i--) {
if (windows[i].x1 <= x && x <= windows[i].x2 &&
windows[i].y1 <= y && y <= windows[i].y2) {
index = i;
break;
}
}
return index;
}
}
链表实现
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Scanner;
public class Main {
static class Window {
int id;
int x1, x2, y1, y2;
public Window(int id, int x1, int x2, int y1, int y2) {
this.id = id;
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
}
}
static int n, m;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
LinkedList<Window> windowsList = new LinkedList<>(); // 使用链表存储窗口
n = scanner.nextInt();
m = scanner.nextInt();
for (int i = 1; i <= n; i++) {
int x1 = scanner.nextInt();
int y1 = scanner.nextInt();
int x2 = scanner.nextInt();
int y2 = scanner.nextInt();
windowsList.addFirst(new Window(i, x1, x2, y1, y2)); // 插入头部
}
while (m-- > 0) {
int x = scanner.nextInt();
int y = scanner.nextInt();
boolean found = false;
Iterator<Window> iterator = windowsList.iterator();
// 从链表头部(最上方)开始遍历
while (iterator.hasNext()) {
Window w = iterator.next();
if (x >= w.x1 && x <= w.x2 && y >= w.y1 && y <= w.y2) {
// 找到点击的窗口
iterator.remove(); // 从当前位置移除
windowsList.addFirst(w); // 移到链表头部(最上方)
System.out.println(w.id);
found = true;
break;
}
}
if (!found) {
System.out.println("IGNORED");
}
}
}
}
二进制王国
思路
- 题目目标
- 给定
N个由'0'和'1'组成的字符串(代表家庭) - 要将这些字符串拼接成一个长字符串
- 目标是:拼接后的结果字典序最小
- 错误直觉 & 正确
- ❌ 错误做法:直接对字符串数组进行自然排序(
Arrays.sort(strings))- 例如:
"11"和"110",虽然"11" < "110",但拼接时"11011"要比"11110"更小
- 例如:
- ✅ 正确策略:贪心思想 —— 比较两个字符串拼接后的结果(自定义比较函数)
我们要定义一种新的比较方式:
如果s1 + s2 < s2 + s1(字典序),则s1应该排在s2前面
否则s2排在前面
参考代码
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
String[] strings = new String[n];
for (int i = 0; i < n; i++) {
strings[i] = scanner.next();
}
Arrays.sort(strings, (s1, s2) -> (s1 + s2).compareTo(s2 + s1));
for (int i = 0; i < n; i++) {
System.out.print(strings[i]);
}
}
}
额外知识点:自定义排序(Comparator)
🎯 这是算法竞赛中的高频技巧!
- 为什么要用自定义排序?
- 默认排序(如字符串自然序)不满足题目要求
- 我们需要根据特定逻辑决定元素之间的先后关系
- Java 中如何实现?
使用 Arrays.sort(T[], Comparator<T>)这两个参数其实是 Arrays.sort(数组, 比较器);
这里的“比较器”就是一个规则说明书,告诉 sort 函数:给你两个元素,你怎么判断谁应该排在前面?
简单来说, 比较器是一个叫compareTo会给你两个参数 a, b根据返回值决定排序
compareTo 返回值怎么看?记住口诀:
负数:前面的小(a 排前)
正数:后面的小(b 排前)
🛠 方法一:使用匿名内部类(传统写法,逻辑清晰)
Arrays.sort(strings, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
// 我们自定义的规则:
// 如果 s1+s2 < s2+s1,说明 s1 应该排在 s2 前面
String order1 = s1 + s2; // s1 在前
String order2 = s2 + s1; // s2 在前
return order1.compareTo(order2); // 如果order1比order2字典序小, 就会返回小于0的数
}
});
💡 方法二:Lambda 表达式(简化写法)
上面的写法逻辑清晰,但代码较长。Java 8 之后提供了更简洁的写法:
Arrays.sort(strings, (s1, s2) -> (s1 + s2).compareTo(s2 + s1));
这行代码和上面的匿名类是完全等价的!
拆解来看:
(s1, s2)→ 就是compare(String s1, String s2)的参数->→ 意思是“执行下面的操作”(s1 + s2).compareTo(s2 + s1)→ 就是我们写的比较逻辑(同时也是返回值)
所以 Lambda 只是“语法糖”:
它让代码更短,但逻辑和匿名内部类一模一样!
三国游戏
思路
题目目标
- 有三个国家:魏(X)、蜀(Y)、吴(Z),初始士兵数都为 0。
- 有
n个独立事件,每个事件发生会分别给 X、Y、Z 加分。 - 游戏结束后,如果某个国家的士兵数 大于其他两国之和,则该国获胜。
- 比如:
X > Y + Z→ 魏国获胜
- 比如:
- 问:最多可以发生多少个事件,使得至少有一个国家获胜?
- 如果无论如何都没有国家能赢,输出
-1。
✅ 注意:我们不是要让某国一定赢,而是要在“能让某国赢”的前提下,尽可能多地发生事件!
关键转化 —— “获胜条件”如何判断?
原始条件:X > Y + Z
我们可以变形:X - Y - Z > 0
这个差值我们称为 “魏国的净贡献”。
💡 启发:
- 每个事件对魏国的“净贡献” =
A[i] - B[i] - C[i] - 如果我们选择了一组事件,它们的净贡献总和 > 0,那么魏国就赢了!
✅ 所以问题变成了:选尽可能多的事件,使得它们的净贡献总和 > 0
贪心策略 —— 如何选事件最多?
我们要选最多的事件,同时保证总净贡献 > 0。
贪心思想:
- 优先选“净贡献大”的事件,这样可以用尽量少的“负贡献”事件来凑数量。
- 具体做法:
- 把所有事件按“净贡献”从大到小排序
- 从最大的开始累加
- 只要累计和 > 0,就可以继续选
- 一旦累计和 ≤ 0,就不能再选了(否则不满足获胜条件)
举例说明(魏国视角):
| 事件 | A | B | C | 净贡献 (A-B-C) |
|---|---|---|---|---|
| 1 | 1 | 2 | 1 | 1-2-1 = -2 |
| 2 | 2 | 3 | 0 | 2-3-0 = -1 |
| 3 | 2 | 2 | 7 | 2-2-7 = -7 |
排序后:[-1, -2, -7](升序),我们从后往前加:
- 加
-1→ sum = -1 ❌ 不大于 0 → 一个都不能选!
这里所有净贡献都是负的,加起来肯定 ≤ 0,所以魏国不可能赢。
上面是魏国的情况。我们还要看蜀国和吴国是否可能赢。
- 蜀国赢:
Y > X + Z→Y - X - Z > 0 - 吴国赢:
Z > X + Y→Z - X - Y > 0
所以我们对每个国家:
- 计算每个事件对该国的“净贡献”
- 排序,从大到小累加
- 统计最多能选多少个事件,使得总净贡献 > 0
最后取三个结果中的最大值。
✅ 如果最大值是 0,说明没人能赢,输出 -1
验证样例
样例输入:
3
1 2 2 ← A (魏)
2 3 2 ← B (蜀)
1 0 7 ← C (吴)
蜀国视角(Y > X+Z):
净贡献 = B - A - C
- 事件1: 2-1-1 = 0
- 事件2: 3-2-0 = 1
- 事件3: 2-2-7 = -7
排序:[-7, 0, 1]从后往前:
- 加 1 → sum=1 > 0 → count=1
- 加 0 → sum=1 > 0 → count=2
- 加 -7 → sum=-6 ≤ 0 → 停止
→ 蜀国最多选 2 个事件(事件2 和 事件1)
吴国视角(Z > X+Y):
净贡献 = C - A - B
- 事件1: 1-1-2 = -2
- 事件2: 0-2-3 = -5
- 事件3: 7-2-2 = 3
排序:[-5, -2, 3]
- 加 3 → sum=3 > 0 → count=1
- 加 -2 → sum=1 > 0 → count=2
- 加 -5 → sum=-4 ≤ 0 → 停止
→ 吴国最多 2 个事件
✅ 最大值 = max(0, 2, 2) = 2 → 输出 2
参考代码
数据类型注意:用 long!
题目中 A[i], B[i], C[i] ≤ 10^9,n ≤ 10^5,总和最大可达 10^9 * 10^5 = 10^14,远超 int 范围(约 2×10⁹),必须使用 long 存储贡献和累计和!
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取事件数量
int n = scanner.nextInt();
// 读取三个国家的得分数组
long[] A = new long[n]; // 魏国X
long[] B = new long[n]; // 蜀国Y
long[] C = new long[n]; // 吴国Z
for (int i = 0; i < n; i++) {
A[i] = scanner.nextLong();
}
for (int i = 0; i < n; i++) {
B[i] = scanner.nextLong();
}
for (int i = 0; i < n; i++) {
C[i] = scanner.nextLong();
}
// 分别计算三个国家能获胜的最大事件数
int resultX = calculateMaxEvents(n, A, B, C, 0); // 魏国X
int resultY = calculateMaxEvents(n, A, B, C, 1); // 蜀国Y
int resultZ = calculateMaxEvents(n, A, B, C, 2); // 吴国Z
// 取三个结果中的最大值
int maxResult = Math.max(resultX, Math.max(resultY, resultZ));
// 如果最大值是0,说明没有国家能获胜,输出-1
System.out.println(maxResult > 0 ? maxResult : -1);
}
/**
* 计算某个国家能获胜的最大事件数
* @param n 事件总数
* @param A 魏国得分数组
* @param B 蜀国得分数组
* @param C 吴国得分数组
* @param country 国家标识:0-魏,1-蜀,2-吴
* @return 该国家能获胜的最大事件数
*/
private static int calculateMaxEvents(int n, long[] A, long[] B, long[] C, int country) {
// 计算每个事件对该国家的纯贡献
long[] contributions = new long[n];
for (int i = 0; i < n; i++) {
switch (country) {
case 0: // 魏国X:X > Y + Z => X - Y - Z > 0
contributions[i] = A[i] - B[i] - C[i];
break;
case 1: // 蜀国Y:Y > X + Z => Y - X - Z > 0
contributions[i] = B[i] - A[i] - C[i];
break;
case 2: // 吴国Z:Z > X + Y => Z - X - Y > 0
contributions[i] = C[i] - A[i] - B[i];
break;
}
}
// 将纯贡献从大到小排序
Arrays.sort(contributions);
// 从大到小累加贡献,直到总和<=0为止
long sum = 0;
int count = 0;
// 从最大的贡献开始累加(因为数组是升序排列,所以从后往前遍历)
for (int i = n - 1; i >= 0; i--) {
sum += contributions[i];
if (sum > 0) {
count++; // 如果总和仍然大于0,可以继续选择事件
} else {
break; // 一旦总和<=0,就不能再选择更多事件了
}
}
return count;
}
}
阶乘求和
思路
题目要求:
S = 1! + 2! + 3! + ... + 202320232023!的末尾9位数字。
✅ 末尾9位 = 对 10^9 取模,即 S % 1000000000
关键观察 —— 阶乘末尾的“0”越来越多!
我们先看几个小例子:
- 5!=120 → 末尾1个0
- 10!=3628800 → 末尾2个0
- 15 → 末尾更多0……
👉 为什么阶乘末尾会有0?
- 因为 10=2×5,每多一对因子 2 和 5,就多一个末尾0。
- 在阶乘中,因子2的个数远多于因子5,所以末尾0的个数由因子5的个数决定。
什么时候阶乘的末尾至少有9个0?
我们来数一数从 1 到 x 的阶乘中,有多少个因子5:
| 数字 | 是否贡献因子5 | 贡献个数 |
|---|---|---|
| 5 | 是 | 1 |
| 10 | 是 | 1 |
| 15 | 是 | 1 |
| 20 | 是 | 1 |
| 25 | 是(25=5×5) | 2 |
| 30 | 是 | 1 |
| 35 | 是 | 1 |
| 40 | 是 | 1 |
累计到 40! :
- 总共贡献了:1+1+1+1+2+1+1+1 = 9 个因子5
- 所以 40! 至少有 9 个末尾0
✅ 这意味着: 40! 是 10^9 的倍数!
因此: 40! \mod 10^9 = 0 \ 41! = 41 \times 40! \Rightarrow 41! \mod 10^9 = 0 \ \vdots \ 202320232023! \mod 10^9 = 0
大发现!只需计算前40项!
因为从 40! 开始,所有阶乘对 10^9 取模都是 0,不会影响最终结果的末尾9位。
所以我们只需要计算: S \mod 10^9 = (1! + 2! + \cdots + 39!) \mod 10^9
这个计算量非常小,完全可以暴力模拟!
注意点
| 注意点 | 说明 |
|---|---|
| ✅ 不要直接算大阶乘! | 202320232023! 是天文数字,根本无法存储。必须利用数学性质优化。 |
| ✅ 末尾0的个数由因子5决定 | 这是经典结论,记住:每5个数贡献1个5,每25个数额外再贡献1个……但本题只需数到40即可。 |
| ✅ 一旦阶乘能被 10^9 整除,后续都为0 | 这是本题最关键的剪枝思想!从40开始的所有项都可以忽略。 |
| ✅ 边算边取模,防止溢出 | 虽然我们只算到40,但 fac 和 sum 仍可能很大,必须用 long 并及时 % MOD。 |
| ✅ MOD = 1_000_000_000 | 写成 1000000000 容易数错位数,Java 中可用 1_000_000_000 提高可读性。 |
参考代码
public class Main {
public static void main(String[] args) {
// 2 * 5 == 10
// 4 * 5 其实就是2*2*5==10
// 而对于阶乘来说 1*2*3*4*5 到这里就会多一个0, 然后继续*6*7*8*9*10又会多一个0, 也就是变成了xx00
// 我们要求的是某个数字x%1e9
// 考虑一下如果某个数字x!末尾大于9个0, 也就是以9个0接尾
// 这个数x!可以被表示成a * 1e9, 然后这个数字再取余, x*1e9 % 1e9==0
// 所以如果某个数字x!末尾产生了9个0, 这个数字取余后的结果就是0
// 现在要找的就是这个产生了9个0的x!的x到底是谁, 简单推一下:
// 阶乘:1*2*3*..5..10..15..20..25..30..35..40
// 产生0的个数:..1..1...1...1...2...1...1...1
// 到这里就已经有9个0了, 也就是40!末尾有9个0, 40!%1e9==0, 换句话说40!%1e9这一项对于结果没有影响, 后面同理, 41, 42等等的阶乘%1e9都对结果没有影响, 那么我们只需要求1到40的这些就行了: 1!%1e9 + 2!%1e9 + ... 40!%1e9
// 这就算的很快了, 直接输出结果
int MOD = 1000000000;
long sum = 0;
long fac = 1;
for (int i = 1; i <= 40; i++) {
fac = (fac * i) % MOD;
sum = (sum + fac) % MOD;
}
System.out.println(sum);
}
}
被替换的身份证
思路步骤
每人两张牌,浅梦先手,谁先出完谁赢。
浅梦能赢的情况只有三种:
- 她有 王炸(MF 或 FM) → 一招秒杀
- 她有 对子(两张一样) → 一次性出完
- 她的 最大单牌 ≥ 沐风的最大单牌,且沐风没有王炸
→ 她先出最大牌,沐风无法响应,她再出第二张赢
其他所有情况,沐风都能赢。
参考代码
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt(); // 读取测试用例数量
// 创建一个 map, 用来表示每张牌的大小顺序
// 数字越小表示牌越小, 方便比较
Map<Character, Integer> rank = new HashMap<>();
rank.put('3', 3);
rank.put('4', 4);
rank.put('5', 5);
rank.put('6', 6);
rank.put('7', 7);
rank.put('8', 8);
rank.put('9', 9);
rank.put('X', 10); // X 代表 10
rank.put('J', 11); // J (Jack)
rank.put('Q', 12); // Q (Queen)
rank.put('K', 13); // K (King)
rank.put('A', 14); // A (Ace)
rank.put('2', 15); // 2 比 A 大
rank.put('M', 16); // M (Black Joker)
rank.put('F', 17); // F (Red Joker) —— 最大
// 处理 T 组测试数据
while (T-- > 0) {
String qm = sc.next(); // 浅梦的两张牌
String mf = sc.next(); // 沐风的两张牌
// 情况1: 浅梦有王炸(MF 或 FM)-> 直接获胜
boolean isQMWangZha = (qm.equals("MF") || qm.equals("FM"));
// 情况2: 浅梦有对子(两张牌一样)-> 直接出完获胜
boolean isQMPair = (qm.charAt(0) == qm.charAt(1));
// 如果是王炸或对子, 浅梦直接赢
if (isQMWangZha || isQMPair) {
System.out.println("ShallowDream");
continue; // 跳过后续判断
}
// 情况3: 浅梦出单张, 看能否压制沐风
// 先找出浅梦两张牌中较大的那张
char qmCard1 = qm.charAt(0);
char qmCard2 = qm.charAt(1);
int maxQm = Math.max(rank.get(qmCard1), rank.get(qmCard2));
// 再找出沐风两张牌中较大的那张
char mfCard1 = mf.charAt(0);
char mfCard2 = mf.charAt(1);
int maxMf = Math.max(rank.get(mfCard1), rank.get(mfCard2));
// 判断沐风是否有王炸
boolean isMFWangZha = (mf.equals("MF") || mf.equals("FM"));
// 如果浅梦的最大单牌 >= 沐风的最大单牌, 且沐风没有王炸
// 那么浅梦先出最大牌, 沐风无法响应, 浅梦下一轮出完获胜
if (maxQm >= maxMf && !isMFWangZha) {
System.out.println("ShallowDream");
} else {
// 其他所有情况, 沐风都能赢
System.out.println("Joker");
}
}
}
}
小蓝的漆房
思路步骤
目标:把一排房子涂成同一种颜色,每天只能涂一个长度为 k 的连续区间。
问:最少需要多少天?
核心策略:枚举最终颜色 + 贪心覆盖
- 颜色种类最多只有 60 种(
1~60),我们可以枚举每一种颜色作为最终目标颜色 - 对每种颜色,计算:从左到右,最少需要多少天才能把整条走廊都变成这种颜色
- 然后取所有颜色中的最小天数,就是答案
贪心策略(对某一目标颜色):
从左往右扫描:
- 如果当前房子已经是目标颜色 → 不用管,跳过
- 如果当前房子不是目标颜色 → 必须涂!
- 从这个房子开始,向右涂
k个房子(即一个区间) - 涂完后,天数 +1
- 然后继续往后扫描
- 从这个房子开始,向右涂
✅ 为什么贪心是对的?
因为越往左越早处理,能覆盖更多未达标的位置,不会浪费操作。
参考代码
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt(); // 测试用例数量
while (T-- > 0) {
int n = sc.nextInt(); // 房子数量
int k = sc.nextInt(); // 每天能涂的长度
int[] colors = new int[n]; // 每个房子的初始颜色
for (int i = 0; i < n; i++) {
colors[i] = sc.nextInt();
}
// 记录所有可能的目标颜色(1 到 60)
// 我们尝试让整条走廊变成 color 1, 2, ..., 60, 看看哪种最省天数
int minDays = Integer.MAX_VALUE;
// 枚举每一种可能的最终颜色(1 到 60)
for (int color = 1; color <= 60; color++) {
// 模拟从左到右涂色的过程
// 使用一个数组来表示当前每间房子的颜色(模拟涂色结果)
int[] currentColors = Arrays.copyOf(colors, n);
int days = 0; // 涂色天数
// 从左到右扫描每间房子
for (int i = 0; i < n; i++) {
// 如果当前房子已经是目标颜色, 不需要涂
if (currentColors[i] == color) {
continue;
}
// 如果当前房子不是目标颜色, 必须涂!
// 从位置 i 开始, 向右涂 k 个房子
// 注意: 不能越界
for (int j = i; j < i + k && j < n; j++) {
currentColors[j] = color;
}
// 涂一次, 天数 +1
days++;
}
// 更新最小天数
minDays = Math.min(minDays, days);
}
// 输出当前测试用例的最少天数
System.out.println(minDays);
}
}
}