小苯的最小好数
[题目链接](https://www.nowcoder.com/practice/9ae46830704e4d2399f025074ffcb949)
思路
给定正整数 ,求不小于
的最小"好数",即所有数位互不相同的数。
回溯(DFS)逐位试填
从最高位到最低位,依次尝试填入数字。核心思想类似数位 DP 中的"贴上界":
- 贴上界阶段:如果前面所有位都和原数一样(还没有变大),当前位只能从
对应位的数字开始往上尝试,不能更小。
- 松弛阶段:一旦某一位填了比原数更大的数字,后续所有位可以从
开始自由选取(只要没被用过)。
- 去重约束:用一个布尔数组记录
哪些数字已经使用,保证每个数字至多出现一次。
如果所有位都尝试完仍然失败(比如原数位数为 但无法构造出
位的好数),则答案一定是
位的最小好数,即
(取前
位)。这是因为好数最多有
位(数字
各用一次),所以只要位数不超过
,一定存在解。
样例演示
输入 :
- 第 0 位:尝试
,标记已用,进入下一位
- 第 1 位:尝试
,标记已用,进入下一位
- 第 2 位:尝试
,标记已用,进入下一位
- 第 3 位:需要
,但
已用,尝试
,可用,填入
- 所有位填完,结果为
复杂度分析
- 时间复杂度:每组数据最坏
,但由于剪枝,实际远小于此。
- 空间复杂度:
,
为数字位数,递归栈深度。
代码
#include <bits/stdc++.h>
using namespace std;
bool dfs(string &num, int i, bool loose, vector<bool> &used) {
if (i == (int)num.size()) return true;
int lo = loose ? 0 : (num[i] - '0');
char orig = num[i];
for (int d = lo; d <= 9; d++) {
if (!used[d]) {
used[d] = true;
num[i] = '0' + d;
if (dfs(num, i + 1, loose || (d > lo), used))
return true;
num[i] = orig;
used[d] = false;
}
}
return false;
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
char buf[20];
scanf("%s", buf);
string num(buf);
vector<bool> used(10, false);
if (dfs(num, 0, false, used)) {
printf("%s\n", num.c_str());
} else {
string fail = "1023456789";
printf("%s\n", fail.substr(0, num.size() + 1).c_str());
}
}
return 0;
}
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
int t = Integer.parseInt(br.readLine().trim());
String fail = "1023456789";
while (t-- > 0) {
char[] num = br.readLine().trim().toCharArray();
boolean res = dfs(num, 0, false, new boolean[10]);
if (res) {
sb.append(new String(num));
} else {
sb.append(fail.substring(0, num.length + 1));
}
sb.append('\n');
}
System.out.print(sb);
}
static boolean dfs(char[] num, int i, boolean loose, boolean[] used) {
if (i == num.length) return true;
int lo = loose ? 0 : (num[i] - '0');
char orig = num[i];
for (int d = lo; d <= 9; d++) {
if (!used[d]) {
used[d] = true;
num[i] = (char) ('0' + d);
if (dfs(num, i + 1, loose || d > lo, used))
return true;
num[i] = orig;
used[d] = false;
}
}
return false;
}
}

京公网安备 11010502036488号