JAVA进步一点点--数据结构与算法(深搜、回溯)-全排列、回溯树

全排列

全排列是深搜/回溯的一个大类,

  1. 全排列
    JAVA进步一点点--数据结构与算法(深搜、回溯)-全排列、回溯树_第1张图片
    关注点:(1)result.add(new ArrayList<>(tmp));直接添加List时,会为空
	List<List<Integer>> result = new ArrayList<>();

	public List<List<Integer>> permute(int[] nums) {
		List<Integer> tmp = new ArrayList<>();
		tracback(nums, tmp);
		return result;
	}

	public void tracback(int[] nums, List<Integer> tmp) {
		if (tmp.size() == nums.length) {
			result.add(new ArrayList<>(tmp));
			return;
		}
		//列出当前可选的所有路径
		for (int i = 0;i<nums.length;i++){
			//对路径进行剪枝,可以使用visited去记录
			if (!tmp.contains(nums[i])){
				//添加当前节点
				tmp.add(nums[i]);
				//添加当前节点的情况下继续回溯
				tracback(nums,tmp);
				//不使用当前节点了,继续下一个选择
				tmp.remove(tmp.size() - 1);
			}
		}
	}

47. 全排列 II
JAVA进步一点点--数据结构与算法(深搜、回溯)-全排列、回溯树_第2张图片

https://leetcode-cn.com/problems/count-numbers-with-unique-digits/、JAVA进步一点点--数据结构与算法(深搜、回溯)-全排列、回溯树_第3张图片
此题暴力解法超时,其实回溯也是暴力解法,只是去掉了一些分支
,分析,此题和上面的全排列问题十分相似,n个位置,0-9全排列的可能,还是一个回溯问题,
JAVA进步一点点--数据结构与算法(深搜、回溯)-全排列、回溯树_第4张图片

int result = 0;

	public int countNumbersWithUniqueDigits1(int n) {

		List<Integer> tmp = new ArrayList<>();
		traceback(n, 1, tmp);
		return result + 1;
	}

	public void traceback(int n, int index, List<Integer> tmp) {
		//如果已经到n位了,直接return
		if (index > n) {
			return;
		}
		//首位不为0
		if (index == 1) {
			for (int i = 1; i <= 9; i++) {
				if (tmp.contains(i)) {
					continue;
				} else {
					tmp.add(i);
					result++;
					traceback(n, index + 1, tmp);
					tmp.remove(tmp.size() - 1);
				}
			}
		} else {
			for (int i = 0; i <= 9; i++) {
				if (tmp.contains(i)) {
					continue;
				} else {
					tmp.add(i);
					result++;
					traceback(n, index + 1, tmp);
					tmp.remove(tmp.size() - 1);
				}
			}
		}
	}

动态规划解法:
我们知道总共的数字可能,那么其中重复多少,不重复多少列表如下:
对于正好有3位重复的个数可以按照下面的式子获取
假设前两位已经重复时,第3为选择0-9任意位置910=90
假设前面两位不重复时,则第3位只能从已经选择的两位中选择一个,81
2=162
即正好有3位时重复的数字为162+90=252,正好有3位的数字为100-999,900种可能,包含252重复的,不重复的为900-252=648,则3位总共的不重复数字为10+81+648=739
在这里插入图片描述
力扣中的答案有一个很奇怪的一点,0位时返回数量是1,哪位大神知道的话,可以给小弟留言。

    public int countNumbersWithUniqueDigits(int n) {
		if (n==0){
			return 1;
		}
		if (n==1){
			return 10;
		}
		int[][] dp = new int[2][n];
		dp[0][0] = 0;
		dp[1][0] = 10;
		dp[0][1] = 9;
		dp[1][1] = 81;
		for (int i = 2; i < n; i++) {
			double zongNum = 9 * Math.pow(10, i);
			dp[0][i] = dp[0][i - 1] * 10 + dp[1][i - 1] * i;
			dp[1][i] = (int) zongNum - dp[0][i];
		}
		return Arrays.stream(dp[1]).sum();
    }

分隔回文串
https://leetcode-cn.com/problems/palindrome-partitioning/
JAVA进步一点点--数据结构与算法(深搜、回溯)-全排列、回溯树_第5张图片
找到下面的回溯树的话,和全排列的问题又一样了,是1-length-1的组合,选择还是不选择的问题。
JAVA进步一点点--数据结构与算法(深搜、回溯)-全排列、回溯树_第6张图片

你可能感兴趣的:(算法与数据结构)