首先奇数位肯定不行,位数直接加一再进行后续判断
偶数的话使用回溯法,
结果肯定类似于110022这样有连续俩个数字的情况,不能有四个连续的数字(题目中说了恰好),所以有这几种情况,将连续两个数字看成一个块
受限选择:当前块需不小于x的对应两位数字,计算最小可能数字。
自由选择:一旦某块大于x对应部分,后续块可自由选择最小数字(跳过前驱块数字)。
回溯:若当前块无解,回溯到前一块并增大数字。 剩下的就好处理了
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String x = scanner.next();
String result = findSmallestTwin(x);
System.out.println(result);
}
public static String findSmallestTwin(String x) {
int n = x.length();
// 处理奇数位数情况:构造 n+1 位的最小双生数
if (n % 2 == 1) {
return generateSmallestTwin((n + 1) / 2);
}
// 处理偶数位数情况
int k = n / 2;
int[] res = new int[k]; // 存储每个块选择的数字
Arrays.fill(res, -1); // 初始化为-1(未选择)
int prev = -1; // 前一个块的数字(无前驱时为-1)
boolean flag = false; // 是否已大于x
int i = 0; // 当前块索引
// 回溯法选择块
while (i >= 0 && i < k) {
if (res[i] != -1) {
// 回溯重新选择当前块
int last_choice = res[i];
res[i] = -1;
flag = true; // 重新选择会增大,后续可自由选择
int next_d = -1;
for (int d = last_choice + 1; d <= 9; d++) {
if (i == 0 && d < 1) continue;
if (prev != -1 && d == prev) continue;
next_d = d;
break;
}
if (next_d != -1) {
res[i] = next_d;
prev = next_d;
i++; // 处理下一块
} else {
// 当前块无法重新选择,回溯到前一块
i--;
if (i >= 0) {
prev = (i > 0) ? res[i - 1] : -1;
}
}
} else {
if (flag) {
// 自由选择:选择最小可用数字
int start = (i == 0) ? 1 : 0;
int d_found = -1;
for (int d = start; d <= 9; d++) {
if (prev != -1 && d == prev) continue;
d_found = d;
break;
}
if (d_found != -1) {
res[i] = d_found;
prev = d_found;
i++;
} else {
// 理论上自由选择总有解,此处为安全回溯
i--;
if (i >= 0) {
prev = (i > 0) ? res[i - 1] : -1;
}
}
} else {
// 受限选择:需不小于x的对应部分
String twoDigits = x.substring(2 * i, 2 * i + 2);
int t = Integer.parseInt(twoDigits);
int d_min = (t + 10) / 11; // 向上取整
if (i == 0 && d_min < 1) d_min = 1;
int d_found = -1;
for (int d = d_min; d <= 9; d++) {
if (i == 0 && d < 1) continue;
if (prev != -1 && d == prev) continue;
d_found = d;
break;
}
if (d_found != -1) {
res[i] = d_found;
if (d_found * 11 > t) flag = true; // 后续可自由选择
prev = d_found;
i++;
} else {
// 当前块无解,回溯
i--;
if (i >= 0) {
prev = (i > 0) ? res[i - 1] : -1;
}
}
}
}
}
if (i < 0) {
// n位无解,构造n+2位双生数
return generateSmallestTwin((n + 2) / 2);
} else {
// 构造结果字符串
StringBuilder sb = new StringBuilder();
for (int d : res) {
sb.append(d).append(d);
}
return sb.toString();
}
}
// 生成指定块数的最小双生数(交替的"11"和"00"块)
private static String generateSmallestTwin(int k) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < k; i++) {
sb.append((i % 2 == 0) ? "11" : "00");
}
return sb.toString();
}
}