题解 | #Sudoku#回溯+剪枝
Sudoku
https://www.nowcoder.com/practice/78a1a4ebe8a34c93aac006c44f6bf8a1
import java.math.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.stream.*;
import java.util.regex.*;
import java.util.function.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String[][] m = new String[9][9];
for (int i = 0; i < 9; i++) {
m[i] = in.nextLine().split(" ");
}
fulfill(m);
Arrays.stream(m).forEach(a-> {
System.out.println(String.join(" ", a));
});
}
// 回溯
static boolean fulfill(String[][] m) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
String curr = m[i][j];
if ("0".equals(curr)) {
// 剪枝
List<String> candidates = getCandidates(i, j, m);
if (candidates.isEmpty()) {
return false;
}
// 递归 DFS
for (String c : candidates) {
// continue fulfill 多次尝试
m[i][j] = c;
if (fulfill(m)) {
return true;
}
// 回溯(仅有 37 行是不可以的)
m[i][j] = "0";
}
return false;
}
}
}
return true;
}
static List<String> getCandidates(int i, int j, String[][] m) {
String h = String.join("", m[i]);
List<String> hSet = IntStream.rangeClosed(1, 9)
.mapToObj(String::valueOf)
// n->!h.contains(n) 可以换成 Predicate.not(h::contains)
.filter(n->!h.contains(n))
.collect(Collectors.toList());
String[] vArr = new String[9];
for (int k = 0; k < 9; k++) {
vArr[k] = m[k][j];
}
String v = String.join("", vArr);
List<String> vSet = IntStream.rangeClosed(1, 9)
.mapToObj(String::valueOf)
.filter(n->!v.contains(n))
.collect(Collectors.toList());
String[] bArr = new String[9];
int bIndex = 0;
for (int p = 0; p < 3; p++) {
for (int q = 0; q < 3; q++) {
bArr[bIndex++] = m[(i / 3) * 3 + p][(j / 3) * 3 + q];
}
}
String b = String.join("", bArr);
List<String> bSet = IntStream.rangeClosed(1, 9)
.mapToObj(String::valueOf)
.filter(n->!b.contains(n))
.collect(Collectors.toList());
vSet.retainAll(bSet);
hSet.retainAll(vSet);
return hSet;
}
}
