全排列问题:回溯法

回溯法的注意点:

1,递归调用之后,即递归方法的下一行,一定要进行回溯一级!

2,递归触底之后,也是一定要回溯一级!

·

题目案例:

给你一个数字n,请你生成并返回所有 从 1 到 n 可能的全排列 。你可以 按任意顺序 返回答案。

比如:

输入:n = 3
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

·

思路:

把从1~n的每个数字,抽象成一个以该元素为根节点的多叉树,

以n为4举例,如图:

这是以1为根节点的多叉树:

还有以2、3、4为根节点的多叉树;

DFS该多叉树,记录路径;

如何遍历呢:

比如说,以1为起点:

  •         遍历数组中的元素,将已遍历过的避开,还剩下——2、3、4,将其中一个元素加入路径中,
  •         继续遍历数组中的元素,将已遍历过的避开,还剩下——x、x,将其中一个元素加入路径中,
  •         继续遍历数组中的元素,将已遍历过的避开,还剩下——x,将其中一个元素加入路径中,
  •         路径的长度等于n了,说明递归触底了,此时回溯一级;

注意:上述每一次递归调用之后,即递归方法的下一行,一定要进行回溯一级!

        递归触底了,当然也是要回溯一级。

·

代码演示:

//全排列
public static List<List<Integer>> permute(int n) {

	Set<Integer> alreadyAddedSet=new HashSet<>(); //利用HashSet,存储遍历过的元素,防止重复
	Deque<Integer> deque = new LinkedList<>(); //辅助栈,记录递归的路径
	
	//递归方法:
	helper(alreadyAddedSet, n, deque);

	System.out.println("nodeValList = " + nodeValList);

	return nodeValList;
}


private static List<List<Integer>> nodeValList = new ArrayList<>(); //全排列结果,存储所有的路径;

/**
   * 全排列:
   * @param deque 辅助栈,记录递归的路径;
   * @param hashSet 利用HashSet,存储存储过的元素,防止重复
*/
public static void helper(Set<Integer> alreadyAddedSet,int n, Deque<Integer> deque)  {
	for (int currEle = 1; currEle <= n; currEle++) {
		  //避开已经存储过的元素	
		  if (alreadyAddedSet.contains(currEle)) {
				continue;
		  }else {
                //将当前的元素加入路径:
				alreadyAddedSet.add(currEle);
				deque.push(currEle);

				if (deque.size() < n) {
					  //递归:
					  helper(alreadyAddedSet,n, deque);
					  
					  //递归之后的下一行,切记要回溯一级:
					  //路径回退一级:
					  //因为使用了Set作为防止元素重复遍历,所以Set也要回退一下,退出刚才的元素:
					  alreadyAddedSet.remove(deque.pop());
					  
				}
				//当栈的元素数量==n了, 说明触底了
				else{
					  // 记录这一条路径:
					  nodeValList.add(new LinkedList<>(deque));
					  //触底了,要回溯一级:
					  //路径回退一级:
					  //因为使用了Set作为防止元素重复遍历,所以Set也要回退一下,退出刚才的元素:
					  alreadyAddedSet.remove(deque.pop());
					  return ;
				}

		  }
	}
	return ;
}

·

测试结果:

        输入:3

        

         输入:4

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值