两道有点难的回溯利口题996_37

996. Number of Squareful Arrays

给一个不含负数的整数数组,问有多少种排列组合使数组可开方的。一个数组是可开方的意思是数组中每两个相邻数之和都是可开方的。

Input: [1,17,8]
Output: 2
Explanation:
[1,8,17] and [17,8,1] are the valid permutations.

tags:回溯,排列组合

首先这个题目编号让人心头一紧,然后开始解题,依旧是无敌的回溯法解决:

  1. 和前面的46题很像,不过是多做了点处理
  2. 每次遍历到一个元素时要和上一个元素相加判断是否可开方,如果可以就继续,不可以就往前回溯
  3. 然后可以通过先排序,并在遇到相同元素时跳过来避免得到重复组合
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不重复的数字:

  1. 重要的地方就是在遍历到每个元素时判断是否合法,本质上和上面一题没有区别,只不过更复杂一点
  2. 尝试填入某个数时判断所在行,列,块是否有相同的数,有的话就试下一个数,没有就填入
  3. 当9个数字全部试完都不合法的话就进行回溯
  4. 另一个关键点在于完成数独后必须返回,而不是像之前的题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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值