【每日刷题】回溯-LCHOT100-22、79、代码随想录回溯-19、20

从今天开始打算把每天的刷题进度同步到CSDN上,一是方便管理刷题进度,二是方便二刷时回来看当时的解题思路。
目前一刷按照代码随想录和力扣HOT100来刷的,今日主题是回溯。

1. LC22括号生成

题目链接
思路:
在这里插入图片描述
回溯或也叫DFS过程中,left和right的值在函数传参中改变的,所以不需要单独回溯。

class Solution {
    StringBuilder sb = new StringBuilder();
    List<String> list = new ArrayList<>();
    public List<String> generateParenthesis(int n) {
        backTracking(n, n);
        return list;
    }
    public void backTracking(int left, int right){
        if (left == 0 && right == 0){
            String str = sb.toString();
            list.add(str);
            return;
        }
        if (left > 0){
            sb.append('(');
            backTracking(left-1, right);
            sb.deleteCharAt(sb.length()-1);
        }
        if (right > left){
            sb.append(')');
            backTracking(left, right-1);
            sb.deleteCharAt(sb.length()-1);
        }
        return;
    }
}

2. LC79单词搜索

题目链接
还是用的回溯法。

核心思路:
for循环遍历二维数组,当遍历到的当前值等于字符串的第一个字符时,进入回溯。向下、向上、向右、向左去回溯,找四个方向是否有符合要求的字符串。如有,直接返回true。如没有,则回到最开始的for循环遍历继续遍历二维数组里的下一个字符。
用used数组记录哪个方向已经遍历过了。

两个坑:
1.刚开始只写了backTracking里的代码,没有写exist方法里的for循环,会造成一个问题,如果board[rowIndex][columnIndex]不符合条件时,没有办法使指针移到board里的下一格,只能return false。所以要在exist方法里写for循环,强行使指针不断移动。
2.如果board只有一个字符,且该字符与字符串的第一个字符相等,必须加上最后一个if条件来判断,否则当board只有一个字符时,无论字符串什么内容,都只会返回false。

class Solution {
    StringBuilder sb = new StringBuilder();
    boolean[][] used;
    public boolean exist(char[][] board, String word) {
        used = new boolean[board.length][board[0].length];
        //必须要写这个for循环
        for (int i = 0; i < board.length; i++){
            for (int j = 0; j < board[0].length; j++){
                if (board[i][j] == word.charAt(0)){
                    boolean result = backTracking(board, word, i, j);
                    if (result){
                        return true;
                    }
                }
            }
        }
        return false;
    }
    public boolean backTracking(char[][] board, String word, int rowIndex, int columnIndex){
        if (sb.length() == word.length()){
            return true;
        }
        if (!used[rowIndex][columnIndex] && board[rowIndex][columnIndex] == word.charAt(sb.length())){
            sb.append(board[rowIndex][columnIndex]);
            used[rowIndex][columnIndex] = true;
            boolean result1 = false;
            boolean result2 = false;
            boolean result3 = false;
            boolean result4 = false;
            if (rowIndex <= board.length-2){
                result1 = backTracking(board, word, rowIndex+1, columnIndex); //下
                if (result1){
                    return true;
                }
            }
            if (rowIndex >= 1){
                result2 = backTracking(board, word, rowIndex-1, columnIndex); //上
                if (result2){
                    return true;
                }
            }
            if (columnIndex <= board[0].length-2){
                result3 = backTracking(board, word, rowIndex, columnIndex+1); //右
                if (result3){
                    return true;
                }
            }
            if (columnIndex >= 1){
                result4 = backTracking(board, word, rowIndex, columnIndex-1); //左
                if (result4){
                    return true;
                }
            }
            //很重要:['a'], a --> true;   ['a'], abc --> false
            if (board.length == 1 && board[0].length == 1){
                return (sb.length() == word.length());
            }
            used[rowIndex][columnIndex] = false;
            sb.deleteCharAt(sb.length()-1);
        }
        return false;
    }
}

3. 代码随想录 回溯-20. N皇后

题目链接
思路:
在这里插入图片描述

class Solution {
    char[][] result;
    List<List<String>> list = new ArrayList<>();
    int num = 0;
    public List<List<String>> solveNQueens(int n) {
        result = new char[n][n];
        for (int i = 0; i < n; i++){
            for (int j = 0; j < n; j++){
                result[i][j] = '.';
            }
        }
        backTracking(0, n);
        return list;
    }

    public void backTracking(int rowIndex, int n){
        //终止条件
        if (rowIndex == n){
            if (num == n){
                List<String> path = new ArrayList<>();
                for (int i = 0; i < n; i++){
                    StringBuilder sb = new StringBuilder();
                    for (int j = 0; j < n; j++){
                        sb.append(result[i][j]);
                    }
                    path.add(sb.toString());
                }
                list.add(path);
            }
            return;
        }
        
        for (int colIndex = 0; colIndex < n; colIndex++){
            if (check(rowIndex, colIndex, n)){
                result[rowIndex][colIndex] = 'Q';
                num++;
                backTracking(rowIndex+1, n);
                result[rowIndex][colIndex] = '.';
                num--;
            }
        }
        return;
    }

    //相当于剪枝
    public boolean check(int rowIndex, int colIndex, int n){
        //判断是否同一列
        for (int i = 0; i < rowIndex; i++){
            if(result[i][colIndex] == 'Q'){
                return false;
            }
        }
        //判断是否左对角线
        for (int i = rowIndex-1, j = colIndex-1; i >= 0 && j >= 0; i--, j--){
            if (result[i][j] == 'Q'){
                return false;
            }
        }
        //判断是否右对角线
        for (int i = rowIndex-1, j = colIndex + 1; i >= 0 && j < n; i--, j++){
            if (result[i][j] == 'Q'){
                return false;
            }
        }
        return true;
    }
}

4. 代码随想录 回溯.19重新安排行程

题目链接
如果backTracking所有的情况,返回list.get(0)会导致超时,所以backTracking返回boolean,一旦遇到正确路径就返回,停止搜索。尽管如此,LC上最后一个用例还是超时了,未解决。。。

注意以下这行代码,目的就是对JFK后面的index为1的元素排序,选则最小的那条路径。

Collections.sort(tickets, (a, b) -> a.get(1).compareTo(b.get(1)));
让我们逐步解释:

Collections.sort: 这是 Java 的集合工具类 Collections 中的一个静态方法,用于对集合进行排序。
tickets: 这是要排序的列表对象。
(a, b) -> a.get(1).compareTo(b.get(1)): 这是一个 Lambda 表达式,用于提供比较两个元素的逻辑。在这里,它指定了按照列表中每个元素的索引 1(第二个元素)进行比较。
Lambda 表达式的结构是 (parameters) -> expression 或 (parameters) -> { statements }。在这里,(a, b)Lambda 表达式的参数,a.get(1).compareTo(b.get(1)) 是表达式,表示按索引 1 比较两个元素。

总的来说,这行代码的作用是对 tickets 列表按照每个元素的索引 1 进行升序排序。这假定 tickets 是一个包含列表的列表,而每个内部列表都有至少两个元素(在这里是索引 0 和索引 1)。

注意:在实际使用中,请确保 tickets 不为 null,并且每个内部列表的长度足够大,以防止 IndexOutOfBoundsException 异常。
class Solution {
    //List<List<String>> list = new ArrayList<>();
    List<String> path = new ArrayList<>();
    boolean[] used;
    public List<String> findItinerary(List<List<String>> tickets) {
        used = new boolean[tickets.size()];
        Collections.sort(tickets, (a, b) -> a.get(1).compareTo(b.get(1)));
        path.add("JFK");
        backTracking(tickets);
        
        //return list.get(0);
        return path;
    }

    public boolean backTracking(List<List<String>> tickets){
        if (path.size() == tickets.size()+1){
            //list.add(new ArrayList<>(path));
            return true;
        }
        for (int i=0; i<tickets.size(); i++){
            if (!used[i] && tickets.get(i).get(0).equals(path.get(path.size()-1))){
                used[i] = true;
                path.add(tickets.get(i).get(1));
                if (backTracking(tickets)){
                    return true;
                }
                path.remove(path.size()-1);
                used[i] = false;
            }
        }
        return false;
    }
}
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值