6. 分治、回溯

1 实现和特性

1.1 分治(递归的一种)

先拆分为子问题,最后子结果合并
例如:
在这里插入图片描述

代码模板

在这里插入图片描述

1.2 回溯(Backtracking)

采用试错的思想,尝试分步地去解决一个问题
在分步解决问题的过程中,发现现有分步结果无效时,将取消上一步甚至几步的计算
再通过其他可能的分步方式再次尝试解决
结果:

  1. 找到一个可能存在正确答案
  2. 尝试了所有可能分步后,没有答案

最坏时间复杂度为指数级
典型问题: 八皇后,数独、背包

2 算法题解

1)[50] Pow(x, n)

计算xn
210 == (25)2 --> ((22)*2)2
要注意奇偶性

pow(x, n)
	subproblem: subresult = pow(x, n/2)

merge:
	if n % 2 == 1 {
		result = subresult * subresult * x;奇数的时候
	} else {
		result = subresult * subresult; 偶数的时候

考虑幂为 正、负 、0的三种情况

/*
 * @lc app=leetcode.cn id=50 lang=java
 *
 * [50] Pow(x, n)
 * 分治
 * 
 */

// @lc code=start
class Solution {
    private double fastPow(double x, long n) {
        if (n == 0) {
            return 1.0;
        }
        double half = fastPow(x, n/2);
        if (n % 2 == 0) return half * half; // 当n为偶数
        else return half * half * x;  // n 为奇数(2^5)=(2^2)^2 * 2
    }

    public double myPow(double x, int n) {
        long N = n;
        // 当幂为负数时,x要变为 1/x, 再把n变为正数计算 (1/x)^-n^
        if (N < 0) {
            x = 1 / x;
            N = -N;
        }
        return fastPow(x, N);
    }
}
// @lc code=end

2)[78] 子集

分治:

通过向下递归,每一层就代表给出的数组的第几个元素

  1. 第一层 无1 与有1
  2. 第二层 无2,与有2
import java.util.ArrayList;
import java.util.List;

/*
 * @lc app=leetcode.cn id=78 lang=java
 *
 * [78] 子集
 * 
 */

// @lc code=start
class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        // 给的数组为空就直接返回空,不为空就向下
        if (nums != null) backtrack(res, nums, new ArrayList<Integer>(), 0);
        return res;
    }

    public void backtrack(List<List<Integer>> res, int[] nums, List<Integer> list, int index) {
        // 终止条件:递归层数等于输入数组长度时,代表递归已经到最后一层了,将所有子树的结果合并
        if (index == nums.length) {
            res.add(new ArrayList<Integer>(list));
            return;
        }

        // 两条分支,第一条不加元素
        backtrack(res, nums, list, index + 1);
        list.add(nums[index]);
        // 第二条要加元素
        backtrack(res, nums, list, index + 1);

        // 因为改变的是参数,参数是向下传递的,所以为了不影响上层,最后需要将这层list添加的删除
        list.remove(list.size() - 1);
    }
}
// @lc code=end


2)[51] N皇后

#
# @lc app=leetcode.cn id=51 lang=python3
#
# [51] N皇后
#

# @lc code=start
class Solution:
    # 递归的入口
    def solveNQueens(self, n: int) -> List[List[str]]:
        if n < 1: return []

        self.result = []
        self.cols = set()
        self.pie = set()
        self.na = set()
        self.DFS(n, 0, [])
        return self.generate_result(n)

    def DFS(self, n, row, cur_state):
        # 终止条件:当row到棋盘的最后一层时,所有皇后排列完毕,将所有结果加到结果中
        if row >= n:
            self.result.append(cur_state)
            return 
        # 依次判断当前层每个对角线是否满足皇后唯一
        for col in range(n):
            if col in self.cols or row + col in self.pie or row - col in self.na:
                continue
            # 将皇后放在当前位置,并记录对角线常数
            self.cols.add(col)
            self.pie.add(row + col)
            self.na.add(row - col)
            # 进入下层递归
            self.DFS(n, row + 1, cur_state + [col])

            # 清除递归当前层添加的内容,防止影响上层
            self.cols.remove(col)
            self.pie.remove(row + col)
            self.na.remove(row - col)

    # 棋盘的输出
    def generate_result(self, n):
        board = []
        for res in self.result:
            for i in res:
                board.append("." * i + "Q" + "." * (n - i - 1))

        return [board[i: i + n] for i in range(0, len(board), n)]
# @lc code=end


发布了90 篇原创文章 · 获赞 4 · 访问量 1431

猜你喜欢

转载自blog.csdn.net/weixin_44145258/article/details/103663838