回溯算法相关题目

Q1:LeedCode_77. 组合

题目:

思路:

这是一道组合的题目,让我们从n个数中取出k个数进行组合,我们要利用回朔算法来进行。我们的思路是从1~n中选取一个数来作为第一个数,然后再从2~n中选取一个数作为第个数。我们用代码来表示

代码:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Leedcode_77 {

    public static void main(String[] args) {
        // 打印输出 combine 方法的返回结果
        System.out.println(combine(4, 2));
    }

    // combine 方法,返回一个包含从 1 到 n 中所有可能的长度为 k 的组合的列表
    public static List<List<Integer>> combine(int n, int k) {
        // 定义一个存储结果的列表
        List<List<Integer>> res  = new ArrayList<>();
        // 定义一个存储当前组合的列表
        LinkedList<Integer> path = new LinkedList<>();
        // 递归获取所有组合
        combine(n, k, 1, res, path);
        // 返回结果列表
        return res;
    }

    // 递归获取从 start 到 n 中所有可能的长度为 k 的组合
    public static void combine(int n, int k, int start, List res, LinkedList<Integer> path) {
        // 如果当前组合的长度为 k,就将其加入到结果列表中,并返回
        if (path.size() == k) {
            res.add(new ArrayList(path));
            return;
        }

        // 遍历从 start 到 n 中的所有数字,将其加入到当前组合中,并递归获取下一个数字的组合
        for (int i = start; i <= n ; i++) {
            path.add(i);
            combine(n, k, i + 1, res, path);
            path.removeLast();//回溯操作
        }
    }
}

但是,我们还可以通过剪枝来优化上面的代码。因为,我们4个数选其中2个数,那么我们肯定要有的选,当第一个数是4的时候那么我们没有第二个数来选了,我们就没有必要再选4来当第一个数。我们要选择他来当第一个数,那么他后面必须要有k-path.size()个数来给我们选。那么for循环中的i就得<=n-(k-path.size()) + 1;我们只改变这里就可以对这个回溯算法进行剪枝

优化后代码:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Leedcode_77 {
    public static void main(String[] args) {
        System.out.println(combine(4, 2));
    }

    public static List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> res  = new ArrayList<>();
        LinkedList<Integer> path = new LinkedList<>();
        combine(n, k, 1, res, path);
        return res;
    }

    public static void combine(int n, int k, int start, List res, LinkedList<Integer> path) {
        if (path.size() == k) {
            res.add(new ArrayList(path));
            return;
        }

        for (int i = start; i <= n - (k - path.size()) + 1 ; i++) {//对i的上限改变了
            path.add(i);
            combine(n, k, i + 1, res, path);
            path.removeLast();
        }
    }

}

Q2:LeedCode_216组合总和 III

题目:

思路:

本题和第一题是类似的,就是加了了一个条件,要k个数之和为n,那么我们可以延续第一题的思路,我们先找出所有k个数的组合,再从中找到符合条件的组合。这里也可以用剪枝。就是for循环中i<=9-(k-path.size())。

这个我是这样理解的,我们要选k个数,那么必须要有k个数给你选,才可以。

那么当我们遍历到i时我们还有多少个数给我们选?总共1-9,9个数,那么下标最大就是8,就是 8-(i-1)个。我们还需要几个数呢?我们要k个数,已经选了path.size()个数,那么我们还需要k-path.size()个数。那么,给我们选的数,肯定是要比我们还需要的数要更多才行。所以得到:8-(i-1)>=k-path.size() 。通过移项可以得到:i<=9-(k- path.size()).

代码:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Leedcode_216_组合总和3 {


    public static void main(String[] args) {
        System.out.println(combinationSum3(3, 7));
    }

    public static List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> res = new ArrayList<>();
        LinkedList<Integer> path = new LinkedList<>();
        int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        combinationSum3( k, n, nums, 0,res,path);
        return res;
    }

    public static void combinationSum3( int k, int n, int[] nums, int start,List res,LinkedList<Integer> path) {
        if(sum(path) > n)  return;
        if (path.size() == k) {
            if (sum(path) == n) {
                res.add(new ArrayList<>(path));
                return;
            }
            return; //这里的这个return得加上,不然会报错的,搞了很久!!!
        }

        for (int i = start; i <= 9 - (k - path.size()); i++) {
            path.add(nums[i]);
            combinationSum3( k, n, nums, i + 1,res,path);
            path.removeLast();
        }
    }
    //用来统计,path里面的数相加等于多少
    public static int sum(LinkedList<Integer> path) {
        int ans = 0;
        for (int i = 0; i < path.size(); i++) {
            ans += path.get(i);
        }
        return ans;
    }
}

Q3:LeedCode_17. 电话号码的字母组合

题目:

思路:

我们这里还是回溯法,把所有拼接方法搜索一遍。2~9按键中都有对应的字符串,传进来的是按键之间的组合,我们要求按键对应每个字符串之间的一个组合。 List res用来存储结果集,用StringBuilder str来存每一个组合。

我们要确定递归的深度:这里递归的深度就是,我们传进来几个按键,就会有几个字母组成的字符串,我们可以用str.length() == digits.length()来作为结束条件,但是这样内存消耗更多。我们用一个int index 表示,传进digits遍历到第几个了。例如:传进来“23”,那么index一开始是0,index == 1就结束。因为传进来2个数字,那么我们搜索完两个字符串就结束

单层递归的广度就是每一个数字对应字符串长度,“2”对应的就是3个字母,“9”对应的就是4个字母。

代码:

import java.util.ArrayList;
import java.util.List;

public class Test2 {
    public static void main(String[] args) {
        System.out.println(letterCombinations("23"));
    }

    public static List<String> letterCombinations(String digits) {
        List<String> res = new ArrayList<>();
        if(digits.equals("")) return res; //如果为空直接返回空
        String[] letterStrs = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
        StringBuilder str = new StringBuilder();
        dfs(res, digits, letterStrs, str, 0);
        return res;
    }

    public static void dfs(List res, String digits, String[] letterStrs, StringBuilder str, int index) {
        //深度
        if (index == digits.length()) {  //如果这里选择用str.length()==digits.length(),内存消耗更大
            res.add(str.toString());
            return;
        }
        String letterStr = letterStrs[digits.charAt(index) - '0'];  //每一个数字键对应的字符串联
        int len = letterStr.length();
        for (int i = 0; i < len; i++) {
            str.append(letterStr.charAt(i));
            dfs(res, digits, letterStrs, str, index+ 1);
            str.deleteCharAt(str.length() - 1); //回溯
        }
    }


Q4:LeedCode_39. 组合总和

题目:

思路:

本题和前面的组合总和类似,只是细节上有些不同。这里是数组里面的元素可以无限制选取。我们这里的递归深度就是sum==target,广度就是startIndex 到数组末尾的长度

代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class LeedCode_39_组合总和 {
    public static void main(String[] args) {
        int[] candidates = {2,3,6,7};
        System.out.println(combinationSum(candidates, 7));

    }

    public static List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);
        List<List<Integer>> res = new ArrayList<>();
        LinkedList<Integer> path = new LinkedList<>();
        dfs(res,path,candidates,target,0,0);
        return res;
    }

    public static void dfs(List res, LinkedList path, int[] candidates, int target, int sum,int startIndex) {
        if (sum > target) return;  //如果sum>target,就没有必要再搜索下去了
        if (sum == target) {
            res.add(new ArrayList(path));
            return;
        }

        for (int i = startIndex; i < candidates.length; i++) {
            if(sum + candidates[i] > target) continue;//剪枝
            path.add(candidates[i]);
            sum += candidates[i];
            dfs(res, path, candidates, target, sum ,i);
            path.removeLast();
            sum -= candidates[i];
        }
    }
}

Q5:LeedCode_40. 组合总和 II

题目:

思路:

本题和上面这题的不同点是不能重复取,但是数组中有重复的元素,这样我们在取的时候有可能取到重复的,我们要创建一个used数组来去重,去重是树层去重

代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class LeedCode_40组合总和two {
    public static void main(String[] args) {
        int[] nums = {10, 1, 2, 7, 6, 1, 5};
        System.out.println(combinationSum2(nums, 8));
    }

    public static List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> res = new LinkedList<>();
        LinkedList<Integer> path = new LinkedList<>();
        if (candidates == null) return res;
        Arrays.sort(candidates);
        boolean[] used = new boolean[candidates.length];//用来统计数组中的元素是否被用过
        dfs(res, path, candidates, target, 0, used, 0);
        return res;
    }

    public static void dfs(List res, LinkedList path, int[] candidates, int target, int sum, boolean[] used, int startIndex) {
        if (sum == target) {
            res.add(new ArrayList(path));
            return;
        }

        for (int i = startIndex; i < candidates.length; i++) {
            if (i > 0 && !used[i - 1] && candidates[i] == candidates[i - 1]) continue;
            if (sum + candidates[i] > target) break;  //减枝
            path.add(candidates[i]);
            used[i] = true;
            sum += candidates[i];
            dfs(res, path, candidates, target, sum, used, i + 1);
            path.removeLast();
            used[i] = false;
            sum -= candidates[i];
        }

    }
}

Q6:LeedCode_131. 分割回文串

题目:

思路:

这题和组合的题目很相似,字符串切割的时候,从开始切,到字符串末尾就结束,这里要注意当切到末尾的时候就停止了,切了一次就 得判断是否为回文,是回文就添加到path里面去,不是就搜索下一个分支

代码:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class LeedCode_131分割回文串 {
    public static void main(String[] args) {
        System.out.println(partition("aab"));
    }

    public static List<List<String>> partition(String s) {
        List<List<String>> res = new ArrayList<>();
        if (s == null) return res;
        LinkedList<Integer> path = new LinkedList<>();
        dfs(res,path,s,0);
        return res;
    }

    public static void dfs(List res, LinkedList path , String str,int startIndex) {
        if(startIndex >= str.length()){
            res.add(new ArrayList<>(path));
            return;
        }

        for (int i = startIndex; i <str.length() ; i++) {
            if(check(str,startIndex,i)){
                path.add(str.substring(startIndex,i + 1)); //substring(),截取字符串是[,)所以这里得加上1
                dfs(res,path,str,i +1);
                path.removeLast();
            }else{
                continue;
            }
        }
    }

    //判断是否为回文字符串
    public static boolean check(String str, int start, int end) {
        for (int i = start, j = end; i < j; i++,j--) {
            if (str.charAt(i) != str.charAt(j)){
                return false;
            }
        }
        return true;
    }
}

Q7:LeedCode_93. 复原 IP 地址

题目:

思路:

这也是分割问题:递归深度就是有三个点就可以结束了,宽度就是0到这个字符串的长度

代码:

import java.util.ArrayList;
import java.util.List;

public class LeedCode_93_复原IP地址 {
    public static void main(String[] args) {
        String s = "101023";
        System.out.println(restoreIpAddresses(s));
    }

    public static List<String> restoreIpAddresses(String s) {
        List<String> res = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        sb.append(s);
        dfs(res, 0, sb, 0);
        return res;
    }

    public static void dfs(List res, int startIndex, StringBuilder sb, int pointSum) {
        //当加的“.”有3个就不要继续加了,判断这个点之后面的数是否也合法,如果合法那就直接add进res中
        if (pointSum == 3) {
            if (check(sb.toString(), startIndex, sb.length() - 1)) {
                res.add(sb.toString());
                return;
            }
            return;
        }

        for (int i = startIndex; i < sb.length(); i++) {
            if (check(sb.toString(), startIndex, i)) {
                sb.insert(i + 1, "."); //insert()这个函数是添加在序号前面的,例如:str = aa, insert(str,0)---> .aa
                pointSum++;
                dfs(res, i + 2, sb, pointSum);  //这里的i要+2,因为这里还添加了个“.” 要注意;
                sb.deleteCharAt(i + 1); //回溯过程
                pointSum--;            //回溯过程
            }else{
                break; //如果前面(sb.toString(), startIndex, i)不合法了,那后面就没必要去搜索了
            }
        }
    }

    //判断传入字符串是否符合要求
    public static boolean check(String str, int start, int end) {
        if(start > end ) return false;
        String numStr = str.substring(start, end + 1);
        if(numStr.length() > 3) return false;  //字符串长度超过3,直接返回false;
        if (numStr.length() == 1 && Integer.parseInt(numStr) == 0) return true; //判断只有一个数,且这个数为0
        int ip = Integer.parseInt(numStr);
        if (!(ip + "").equals(numStr)) return false;  //判断是否有前置0;
        if (ip > 255 || ip < 0) return false;
        return true;
    }
}

Q8:LeedCode_78. 子集

题目:

思路:

深度就是startIndex == nums.length() ,宽度就是0到num.length() - 1;这次的结果是在进入下一次递归前就要收集;

代码:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class LeedCode_78子集 {
    public static void main(String[] args) {
     int[] nums = {0};
        System.out.println(subsets(nums));
    }

    public static List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        LinkedList<Integer> path = new LinkedList<>();
        dfs(res,path,nums,0);
        return  res;

    }

    public static void dfs(List res,LinkedList path,int[] nums,int startIndex){

        res.add(new LinkedList<>(path));

        if(startIndex == nums.length){
            return;
        }

        for (int i = startIndex; i < nums.length; i++) {
            path.add(nums[i]);
            dfs(res,path,nums,i+1);
            path.removeLast();
        }
    }


}

Q9:LeedCode_90. 子集 II

题目:

思路:

这是和上一题大体上一样,不过就因为有重复元素所以就要考虑重复的问题,这里我们要用used数组对搜索进行去重即可,看代码

代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class LeedCode_90子集2 {
    public static void main(String[] args) {
    int[] nums  = {1,2,2};
        System.out.println(subsetsWithDup(nums));
    }

    public static List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        LinkedList<Integer> path = new LinkedList<>();
        Arrays.sort(nums);  //对数组进行排序
        boolean[] used = new boolean[nums.length];

        dfs(res,path,nums,0,used);
        return res;
    }

    public static void dfs(List res,LinkedList path , int[] nums,int startIndex , boolean[] used){

        res.add(new LinkedList(path));

        if(startIndex >= nums.length){
            return;
        }

        for (int i = startIndex; i < nums.length; i++) {
            if(i>0 && nums[i] == nums[i - 1] && used[i -1] == false) {
                continue;
            }

            path.add(nums[i]);
            used[i] = true;
            dfs(res,path,nums,i+1,used);
            path.removeLast();
            used[i] = false;
        }
    }
}

Q10:LeedCode_491. 递增子序列

题目:

思路:

本题又是上一题的一个升级,求的也是子集,不过得是递增的,而且他这个数组有可能重复,所以我们还要考虑去重的问题,这里去重 和上面的子集2又不同因为,这里不能通过数组的排序进行去重,我们这里可以用数组进行去重

代码:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class LeedCode_491递增子序列 {
    public static void main(String[] args) {
    int[] nums = {1, 2, 1, 1};
    System.out.println(findSubsequences(nums));
}

    public static List<List<Integer>> findSubsequences(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        LinkedList<Integer> path = new LinkedList();
        dfs(res, path, nums, 0);
        return res;
    }

    public static void dfs(List res, LinkedList<Integer> path, int[] nums, int startIndex) {
        //结束条件
        if (startIndex > nums.length) {
            return;
        }
        //收获结果
        if (path.size() > 1) {
            res.add(new LinkedList<>(path));
        }
        //搜索逻辑
        int[] used = new int[201];   //题目中nums中的值范围是:[-100,100];
        for (int i = startIndex; i < nums.length; i++) {
            if (used[nums[i] + 100] == 1) continue;
            if (!path.isEmpty() && path.getLast() > nums[i]) continue;
            path.add(nums[i]);
            used[nums[i] + 100] = 1;
            dfs(res, path, nums, i + 1);
            path.removeLast();
        }
    }
}

Q11:LeedCode_46. 全排列

题目:

思路:

全排列,我们使用回溯算法,这里要用到used数组来标记元素是否使用,遍历的时候和之前不同了,这里是从头开始,因为这里是排列,比如1,2和2,1是两种排列。所以每次我们都得从0开始遍历,used数组标记了遍历过的就不需要再次遍历了。

代码:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class LeedCode_46全排列 {
    public static void main(String[] args) {
     int[] nums = {1,2,3};
        System.out.println(permute(nums));
    }

    public static List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        LinkedList<Integer> path = new LinkedList<>();
        boolean[] used = new boolean[nums.length];
        dfs(res,path,used,nums);
        return res;
    }

    public static void dfs(List res,LinkedList path,boolean[] used , int[] nums){
        if(path.size() == nums.length){
            res.add(new LinkedList<Integer>(path));
        }

        for (int i = 0; i < nums.length; i++) {
           if(!used[i]){
               used[i] =true;
               path.add(nums[i]);
               dfs(res,path,used,nums);
               used[i] = false;
               path.removeLast();
           }
         }
    }
}

Q12:LeedCode_47. 全排列 II

题目:

思路:

本题和46题就是,这里的nums有重复元素,那么我们要考虑去重,这里也是数层上面的去重,创建used数组,前面的数没有被用过那么我们就不要,那么我们只要这个去重的代码过去就可以解决了

代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class LeedCode_47全排列II {
    public static void main(String[] args) {
     int[] nums = {1,1,3};
        System.out.println(permuteUnique(nums));
    }
    public static List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        LinkedList path = new LinkedList();
        boolean[] used = new boolean[nums.length];
        Arrays.sort(nums);
        dfs(res,path,nums,used);
        return  res;

    }

    public static void dfs(List res,LinkedList path,int[] nums,boolean[] used){
        if(path.size() == nums.length){
            res.add(new LinkedList<>(path));
            return;
        }

        for (int i = 0; i < nums.length; i++) {
           if(i>0 && nums[i] == nums[i-1] && used[i - 1] == false) continue;
            if(!used[i]) {
                used[i] = true;
                path.add(nums[i]);
                dfs(res, path, nums, used);
                used[i] = false;
                path.removeLast();
            }
        }
    }
}

Q13:LeedCode_51. N 皇后

题目:

思路:

这题用搜索的思想,深度就是row到最后一行就结束了,每一行只放一个Q,放完就下一行,我们要先判断这个Q的位置是否合法,然后合法就放置Q,进行下一行的放置

代码:

import java.util.ArrayList;
import java.util.List;

public class LeedCode_51N皇后 {
    public static void main(String[] args) {
        System.out.println(solveNQueens(4));
    }

    public static List<List<String>> solveNQueens(int n) {
        List<List<String>> res = new ArrayList<>();
        char[][] map = new char[n][n];
        //初始化
        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map.length; j++) {
                map[i][j] = '.';
            }
        }
        dfs(0,map,res);
        return res;
    }

    public static void dfs(int row , char[][] map ,List res){
        //终止条件
        if(row == map.length){
         res.add(new ArrayList<>(getList(map)));
         return;
        }

        for (int i = 0; i < map.length; i++) {
           if(isValid(row,i,map)){
               map[row][i] = 'Q';
               dfs(row + 1 ,map,res);
               map[row][i] = '.';
           }
        }

    }
    //检查Q放在(x,y)这个位置是否合法
    public static boolean isValid(int x, int y, char[][] map) {
        //行,列,斜角都不能有Q,那么逐一检查.行可以不检查,因为他是从左往右依次遍历的,不会有重复的
        //检查列
        for (int i = 0; i < x; i++) {
            if (map[i][y] == 'Q') return false;
        }
        //检查左上角
        for (int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--) {
            if (map[i][j] == 'Q') return false;
        }
        //检查右上角
        for (int i = x - 1, j = y + 1; i >= 0 && j < map.length; i--, j++) {
           if (map[i][j] == 'Q')  return false;
        }
        //以上都满足,那么就合法
        return true;
    }

    //把char[][]map 转化为 List<String>
    public static List<String> getList(char[][] map){
        List<String> list = new ArrayList<>();
        for (int i = 0; i < map.length; i++) {
            String str = "";
            for (int j = 0; j < map[i].length; j++) {
                str += map[i][j];
            }
            list.add(str);
        }
        return list;
    }
}

Q13:LeedCode_51. N 皇后

题目:

思路:

递归结束条件就是,当最后一行Q放置完毕就是结束了,我们通过遍历所有位置,看是否Q的位置合法,如果合法,那么就进入下一行进行放置

代码:

import java.util.ArrayList;
import java.util.List;

public class LeedCode_51N皇后 {
    public static void main(String[] args) {
        System.out.println(solveNQueens(4));
    }

    public static List<List<String>> solveNQueens(int n) {
        List<List<String>> res = new ArrayList<>();
        char[][] map = new char[n][n];
        //初始化
        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map.length; j++) {
                map[i][j] = '.';
            }
        }
        dfs(0,map,res);
        return res;
    }

    public static void dfs(int row , char[][] map ,List res){
        //终止条件
        if(row == map.length){
         res.add(new ArrayList<>(getList(map)));
         return;
        }

        for (int i = 0; i < map.length; i++) {
           if(isValid(row,i,map)){
               map[row][i] = 'Q';
               dfs(row + 1 ,map,res);
               map[row][i] = '.';
           }
        }

    }
    //检查Q放在(x,y)这个位置是否合法
    public static boolean isValid(int x, int y, char[][] map) {
        //行,列,斜角都不能有Q,那么逐一检查.行可以不检查,因为他是从左往右依次遍历的,不会有重复的
        //检查列
        for (int i = 0; i < x; i++) {
            if (map[i][y] == 'Q') return false;
        }
        //检查左上角
        for (int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--) {
            if (map[i][j] == 'Q') return false;
        }
        //检查右上角
        for (int i = x - 1, j = y + 1; i >= 0 && j < map.length; i--, j++) {
           if (map[i][j] == 'Q')  return false;
        }
        //以上都满足,那么就合法
        return true;
    }

    //把char[][]map 转化为 List<String>
    public static List<String> getList(char[][] map){
        List<String> list = new ArrayList<>();
        for (int i = 0; i < map.length; i++) {
            String str = "";
            for (int j = 0; j < map[i].length; j++) {
                str += map[i][j];
            }
            list.add(str);
        }
        return list;
    }

}

Q14:LeedCode_37. 解数独

题目:

思路:

每次都遍历整个棋盘,看是否全部填满,填满就返回true

代码:

   public class LeedCode_37解数独 {
    public static void main(String[] args) {
        char[][] board = {
                {'5', '3', '.', '.', '7', '.', '.', '.', '.'},
                {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
                {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
                {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
                {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
                {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
                {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
                {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
                {'.', '.', '.', '.', '8', '.', '.', '7', '9'}
        };

        solveSudoku(board);

    }

    public static void solveSudoku(char[][] board) {
        dfs(board);
    }

    public static boolean dfs(char[][] board) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] != '.') continue; //如果不是空着的,那就下一个数字
                for (char val = '1'; val <= '9'; val++) {
                    if (isValid(i, j, val, board)) {
                        board[i][j] = val;
                        if (dfs(board)) return true;
                        board[i][j] = '.';
                    }
                }
                return false;
            }
        }
        return true;
    }

    public static boolean isValid(int x, int y, char val, char[][] board) {
        //检查行
        for (int i = 0; i < 9; i++) {
            if (board[x][i] == val) return false;
        }
        //检查列
        for (int i = 0; i < 9; i++) {
            if (board[i][y] == val) return false;
        }
        //检查3*3小方块
        int startX = (x / 3) * 3;  //检查小方块,左上角行的index
        int startY = (y / 3) * 3;   //检查小方块,左上角列的index
        for (int i = startX; i < startX + 3; i++) {
            for (int j = startY; j < startY + 3; j++) {
                if (board[i][j] == val) return false;
            }
        }
        //以上都没有问题,返回true;
        return true;
    }


}

回溯算法暂时就写完了,后续更新里面内容,本文是按照代码随想录的刷题顺序,刷题

2023-03-30 by盖亮

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值