五大常用算法--回溯

概念

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。

关键词汇

解空间树、决策树、DFS

伪代码

result = []
def backtrack(路径, 选择列表):
      if 满足结束条件
          result.add(路径)
          return

       for选择 in 选择列表
           做选择   // 相当于二叉树的前序遍历
           backtrack(路径, 选择列表)
           撤销选择 // 相当于二叉树的后序遍历
树遍历
void traverse(TreeNode root) {
    for (TreeNode child : root.childern)
        // 前序遍历需要的操作
        traverse(child);
        // 后序遍历需要的操作
}

经典例子

全排列

package backtracing;

import java.util.ArrayList;
import java.util.List;
// 求n的全排列
public class PermutePrac {
    private List<List<Integer>> listList = new ArrayList<>();

    public List<List<Integer>> permute(int[] nums) {
        int len = nums.length;
        backTrack(new ArrayList<>(), len, nums);
        return listList;
    }

    public void backTrack(List<Integer> list, int n, int[] nums) {
        // 判断回溯值
        if (list.size() == n) {
            listList.add(new ArrayList<>(list));
        }
        // 遍历
        for (int i = 0; i < n; i++) {
            // 约束条件
            if (list.contains(nums[i])) {
                continue;
            }
            list.add(nums[i]);
            backTrack(list, n, nums);
            // 回溯
            list.remove(list.size() - 1);
        }
    }
}

八皇后

package backtracing.nqueen;

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

// leetcode 51
//
// 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
//
// 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
// 
// 示例:
//
// 输入: 4
// 输出: [
// [".Q..",  // 解法 1
// "...Q",
// "Q...",
// "..Q."],
//
// ["..Q.",  // 解法 2
// "Q...",
// "...Q",
// ".Q.."]
// ]

public class Solution {
    List<List<String>> listlist = new ArrayList<>();

    public List<List<String>> solveNQueens(int n) {
        solveNQueenUtil(0, n, new ArrayList<>());
        return listlist;
    }

    private void solveNQueenUtil(int row, int n, List<String> list) {
        if (row == n) {
            listlist.add(new ArrayList<>(list));
            return;
        }

        for (int col = 0; col < n; col++) {
            list.add(generateColn(col, n));
            if (isSafe(list, n)) {
                solveNQueenUtil(row + 1, n, list);
            }
            list.remove(list.size() - 1);
        }
    }

    private String generateColn(int col, int n) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < n; i++) {
            if (i == col) {
                sb.append("Q");
            } else {
                sb.append(".");
            }
        }
        return sb.toString();
    }

    boolean isSafe(List<String> list, int n) {
        return isColSafe(list, n) && isLeftDiagnoseSafe(list, n) && isRightDiagnoseSafe(list, n);
    }

    boolean isColSafe(List<String> list, int n) {
        for (int col = 0; col < n; col++) {
            int count =  0;
            for (int row = 0; row < list.size(); row++) {
                if (list.get(row).charAt(col) == 'Q') {
                    count++;
                }
            }
            if (count > 1) {
                return false;
            }
        }
        return true;
    }

    boolean isLeftDiagnoseSafe(List<String> list, int n) {
        for (int col = 0; col < n; col++) {
            int nextRow = 0;
            int nextCol = col;
            int count = 0;
            if (leftDianoseUtil(list, nextRow, nextCol, count)) return false;
        }

        for (int row = 0; row < list.size(); row++) {
            int nextRow = row;
            int nextCol = n - 1;
            int count = 0;
            if (leftDianoseUtil(list, nextRow, nextCol, count)) return false;
        }
        return true;
    }

    private boolean leftDianoseUtil(List<String> list, int nextRow, int nextCol, int count) {
        while (nextRow < list.size() && nextCol >= 0) {
            if (list.get(nextRow).charAt(nextCol) == 'Q') {
                count++;
            }
            nextCol--;
            nextRow++;
        }
        if (count > 1) {
            return true;
        }
        return false;
    }

    boolean isRightDiagnoseSafe(List<String> list, int n) {
        for (int col = n - 1; col >= 0; col--) {
            int nextRow = 0;
            int nextCol = col;
            int count = 0;
            if (rightDianoseUtil(list, n, nextRow, nextCol, count)) return false;
        }

        for (int row = 0; row < list.size(); row++) {
            int nextRow = row;
            int nextCol = 0;
            int count = 0;
            if (rightDianoseUtil(list, n, nextRow, nextCol, count)) return false;
        }
        return true;
    }

    private boolean rightDianoseUtil(List<String> list, int n, int nextRow, int nextCol, int count) {
        while (nextRow < list.size() && nextCol < n) {
            if (list.get(nextRow).charAt(nextCol) == 'Q') {
                count++;
            }
            nextCol++;
            nextRow++;
        }
        if (count > 1) {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        solution.solveNQueens(4);
        System.out.println(solution.listlist);
    }
}

参考资料:

1. https://leetcode-cn.com/problems/n-queens/solution/hui-su-suan-fa-xiang-jie-by-labuladong/ (主要参考)

2. https://leetcode-cn.com/problems/n-queens/solution/nhuang-hou-by-leetcode/

猜你喜欢

转载自www.cnblogs.com/harry1989/p/12082011.html