996. Number of Squareful Arrays
给一个不含负数的整数数组,问有多少种排列组合使数组可开方的。一个数组是可开方的意思是数组中每两个相邻数之和都是可开方的。
Input: [1,17,8]
Output: 2
Explanation:
[1,8,17] and [17,8,1] are the valid permutations.
tags:回溯,排列组合
首先这个题目编号让人心头一紧,然后开始解题,依旧是无敌的回溯法解决:
- 和前面的46题很像,不过是多做了点处理
- 每次遍历到一个元素时要和上一个元素相加判断是否可开方,如果可以就继续,不可以就往前回溯
- 然后可以通过先排序,并在遇到相同元素时跳过来避免得到重复组合
public int numSquarefulPerms(int[] A) {
boolean[] visited = new boolean[A.length];
Arrays.sort(A);
help(A, visited, 0, new ArrayList<>());
return res;
}
int res = 0;
public void help(int[] A, boolean[] visited, int index, List<Integer> once) {
if (index == A.length) {
res++;
} else {
for (int i = 0; i < A.length; i++) {
if (visited[i]) continue;
//关键就是这句判断和之前不一样,对数字开方看其是不是一个整数
if (once.size() == 0 || ((int)Math.sqrt(once.get(once.size() - 1) + A[i]) - Math.sqrt(once.get(once.size() - 1) + A[i]) == 0)) {
visited[i] = true;
once.add(A[i]);
help(A, visited, index + 1, once);
once.remove(once.size() - 1);
visited[i] = false;
while (i + 1 < A.length && A[i] == A[i+1]) i++;
}
}
}
}
37. Sudoku Solver
给一个数独,填充空白部分。
tags:回溯,排列组合,剪枝
数独大家都知道的东西,就不介绍了。这里的数独是9X9的二维数组,要求每行,每列和每9个小块中就是1到9不重复的数字:
- 重要的地方就是在遍历到每个元素时判断是否合法,本质上和上面一题没有区别,只不过更复杂一点
- 尝试填入某个数时判断所在行,列,块是否有相同的数,有的话就试下一个数,没有就填入
- 当9个数字全部试完都不合法的话就进行回溯
- 另一个关键点在于完成数独后必须返回,而不是像之前的题help不用设返回值,因为这个题是对所给的二维数组自身进行改变,如果不返回值,回溯就会很慢,所以相当于是一种剪枝行为,,吧。其实我也没有完全搞清这个逻辑,之后再看看吧
public void solveSudoku(char[][] board) {
help(board,0,0);
}
public boolean help(char[][] board, int row, int col) {
if (row == 8 && col == 9)
return true;
if (col == 9) {
row++;
col = 0;
}
if (board[row][col] != '.')
return help(board, row, col+1);
//从1到9挨个试一遍,如果可用就直接看下一个格子,
//如果不可用就用后一个数字再试,直到遇到可用的数字,但如果所有数字都不可用就返回false
//所以help(board)== false,把这个格子重新设为空,回溯到上一个格子换个数字后继续下去
for (char i = '1'; i <= '9'; i++) {
if (valid(board, row, col, i)) {
board[row][col] = i;
if (help(board, row, col+1))
return true;
else
board[row][col] = '.';
}
}
return false;
}
//判断填入数字是否合法
public boolean valid(char[][] board, int row, int col, char num) {
for (int i = 0; i < 9; i++) {
if (board[row][i] == num) return false;
if (board[i][col] == num) return false;
if (board[3 * (row / 3) + i / 3][ 3 * (col / 3) + i % 3] == num) return false;
}
return true;
}