具体描述
代码
public class Main {
public static String solution(int[] plates, int n) {
StringBuilder sb = new StringBuilder();
int i = 0;
while (i < n) {
int j = i;
// Find the end of the consecutive increasing sequence
while (j + 1 < n && plates[j + 1] == plates[j] + 1) {
j++;
}
// If the sequence has at least 3 elements, append as range
if (j - i >= 2) {
sb.append(plates[i]).append("-").append(plates[j]);
i = j + 1;
} else {
// Otherwise, append individual numbers
for (int k = i; k <= j; k++) {
sb.append(plates[k]);
if (k < j) sb.append(",");
}
i = j + 1;
}
if (i < n) sb.append(",");
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(solution(new int[]{-3, -2, -1, 2, 10, 15, 16, 18, 19, 20}, 10).equals("-3--1,2,10,15,16,18-20"));
System.out.println(solution(new int[]{-6, -3, -2, -1, 0, 1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20}, 20).equals("-6,-3-1,3-5,7-11,14,15,17-20"));
System.out.println(solution(new int[]{1, 2, 7, 8, 9, 10, 11, 19}, 8).equals("1,2,7-11,19"));
}
}
思路
问题要求将一系列整数(盘子序号)按照一定的规则归类,其中每一组包含连续递增的序列,且序列的长度必须至少为3。若不满足这个条件,单独列出这个盘子。
具体的解决思路如下:
-
遍历数组,查找连续的递增子序列。
-
记录子序列的起始和结束位置:
- 当发现一个连续递增的子序列长度超过等于3时,将该子序列用起始和结束元素表示,如
-3--1。 - 否则,直接将这些元素单独列出。
- 当发现一个连续递增的子序列长度超过等于3时,将该子序列用起始和结束元素表示,如
-
构建最终结果:使用
StringBuilder或StringBuffer拼接结果,确保最终输出的格式正确。 -
注意边界条件,例如数组为空,或者没有任何连续递增的子序列等。
解法分析
-
遍历和识别连续序列:
- 遍历数组,对于每个元素,查看其下一个元素是否是递增的(即
plates[j+1] == plates[j] + 1)。 - 如果是,继续向后搜索,直到序列结束。
- 如果连续子序列的长度小于3,则单独列出这些元素。
- 遍历数组,对于每个元素,查看其下一个元素是否是递增的(即
-
拼接字符串:
- 如果连续子序列的长度大于等于3,将其格式化为
start-end(例如:-3--1)。 - 否则,直接将这些元素添加到结果中,并确保以逗号分隔。
- 如果连续子序列的长度大于等于3,将其格式化为
-
时间复杂度和空间复杂度分析:
- 时间复杂度:由于我们只需要一次遍历整个数组,时间复杂度是 O(n) ,其中
n是数组的长度。 - 空间复杂度:主要是用于保存结果字符串的空间,因此空间复杂度是 O(n) ,用于存储输出字符串。
- 时间复杂度:由于我们只需要一次遍历整个数组,时间复杂度是 O(n) ,其中
分步解析
步骤 1: 初始化变量
首先,我们需要一些变量来存储最终结果并帮助我们遍历数组:
StringBuilder sb = new StringBuilder();
int i = 0;
StringBuilder sb:用来存储最终的结果字符串。StringBuilder比String更高效,因为它支持动态扩展并减少了不必要的字符串拼接操作。int i = 0:用来遍历数组plates的索引。每次找到一个连续的递增序列,我们都将i更新为新的索引位置。
步骤 2: 遍历盘子数组
我们使用 while 循环遍历整个盘子序列,直到处理完所有盘子:
while (i < n) {
int j = i;
int j = i:这里j用来查找连续递增序列的结束位置。从i开始,我们尝试找到一个连续递增的序列。
步骤 3: 查找连续递增序列
接下来,我们使用一个嵌套的 while 循环查找连续递增的序列:
while (j + 1 < n && plates[j + 1] == plates[j] + 1) {
j++;
}
plates[j + 1] == plates[j] + 1:检查plates[j + 1]是否等于plates[j]加1,这意味着盘子序号是连续递增的。j++:如果是递增的,继续向后检查下一个盘子。
j 将指向当前递增序列的最后一个盘子。
步骤 4: 判断序列长度并处理
在找到了一个连续递增的子序列后,我们需要判断这个子序列的长度,并决定是用区间表示还是单独列出。
情况 1:序列长度大于等于 3
如果递增序列的长度大于或等于3,我们将它表示为一个区间 start-end(例如 -3--1):
if (j - i >= 2) {
sb.append(plates[i]).append("-").append(plates[j]);
i = j + 1;
}
j - i >= 2:判断序列的长度。如果长度大于等于3(即j - i >= 2),则我们认为它是一个有效的连续序列。sb.append(plates[i]).append("-").append(plates[j]):将序列的起始和结束盘子编号按区间格式拼接成字符串。i = j + 1:更新i为j + 1,跳到下一个盘子位置。
情况 2:序列长度小于 3
如果递增序列的长度小于3,我们将这些盘子单独列出:
else {
for (int k = i; k <= j; k++) {
sb.append(plates[k]);
if (k < j) sb.append(",");
}
i = j + 1;
}
for (int k = i; k <= j; k++):遍历当前序列中的所有盘子。sb.append(plates[k]):将当前盘子编号添加到结果字符串中。if (k < j) sb.append(","):在每个盘子后面添加逗号,除了最后一个盘子。i = j + 1:更新i,继续处理下一个位置。
步骤 5: 处理逗号
我们需要在每个序列或盘子后加上逗号,除非它是最后一个元素:
if (i < n) sb.append(",");
if (i < n) sb.append(","):如果还有后续元素,则在当前结果后面添加一个逗号。
步骤 6: 返回结果
当遍历完所有盘子后,返回最终构建的字符串:
return sb.toString();
完整实现
public class Main {
public static String solution(int[] plates, int n) {
StringBuilder sb = new StringBuilder();
int i = 0;
while (i < n) {
int j = i;
while (j + 1 < n && plates[j + 1] == plates[j] + 1) {
j++;
}
if (j - i >= 2) {
sb.append(plates[i]).append("-").append(plates[j]);
i = j + 1;
} else {
for (int k = i; k <= j; k++) {
sb.append(plates[k]);
if (k < j) sb.append(",");
}
i = j + 1;
}
if (i < n) sb.append(",");
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(solution(new int[]{-3, -2, -1, 2, 10, 15, 16, 18, 19, 20}, 10)); // "-3--1,2,10,15,16,18-20"
System.out.println(solution(new int[]{-6, -3, -2, -1, 0, 1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20}, 20));
System.out.println(solution(new int[]{1, 2, 7, 8, 9, 10, 11, 19}, 8)); // "1,2,7-11,19"
}
}
时空复杂度
时间复杂度
-
时间复杂度:
- 我们通过一次遍历数组来查找连续递增的子序列。因此时间复杂度为 O(n) ,其中
n是输入数组的长度。
- 我们通过一次遍历数组来查找连续递增的子序列。因此时间复杂度为 O(n) ,其中
-
空间复杂度:
- 使用
StringBuilder拼接结果,最坏情况下需要存储整个数组的序列,所以空间复杂度为 O(n) 。
- 使用
空间复杂度
- 空间使用:
Counter对象的大小与棋子种类数成正比。如果有 K 种不同棋子,空间复杂度为 O(K)。 - 输入数据:输入数组本身占用 O(N)。
- 总复杂度:O(N+K),通常 K≪N。
总结
解决这类问题时,核心是将复杂问题拆解成更小、更易处理的子问题。在本题中,关键是将连续递增的序列从整个数组中提取出来,然后根据序列长度的不同采取不同的策略。这种分治法的思想可以让问题变得更加简洁明了。例如,当连续的盘子序号小于3时,我们不需要做太多处理;当它们满足条件时,我们就把这些盘子作为一个区间输出。