【回溯】数据的全排列(状态重置)

一、题目描述

给定一堆数字,求出它们的全排列.

输入
{123}
输出
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 2, 1]
[3, 1, 2]

二、思路

全排列问题是指给定一个字符串或者数组,求解字符串中字符或数组中数字所有可能出现的排列。我们在数学上碰到这种问题,第一反应肯定是先从1开始,找 [2,3] 的全排列;然后从2开始,找 [3] 的全排列;以此类推,显然最后变成了一个递归问题。

(1) 状态重置(交换)

import java.util.Arrays;

public class permutation {
  private static void swap(int[] array,int start,int i){
    int t = array[start];
    array[start] = array[i];
    array[i] = t;
  }
   
  public static void main(String[] args){
    int[] array=new int[]{1,2,3};
    permute(array, 0);
  }
  
  public static void permute(int[] array,int start){
    if(start == array.length) {
      System.out.println(Arrays.toString(array));
	  return;
	}
    for(int i = start; i < array.length; ++i) {
       swap(array, start, i);     
       permute(array, start+1);
       swap(array, start, i);
   	}
  }
}

这里讲一下大概的逻辑

  • 首先数组 arr[1, 2, 3],第一次交换不会发生变化,因为 start == i

  • 进入第一次 permute 递归 (start == 1),i == start == 1,也是没有交换,第二次递归,直到 start == 3之前都没有交换,到 start == 3,输出一次排列,第二次递归结束 (start == 2),退回第一次递归 (start == 1),进入第二次循环 (i == start == 1),然后第二遍循环 (i == 2),此时交换有作用 arr[1 , 3, 2].

  • … …

存在的问题:如果数组里面出现重复元素的话,那么 集合 一定会有重复的排列

如果想去掉重复元素那应该如何解决?我们最先想到的可能就是把存储结果的容器换成Set,因为Set的值是唯一的,这样可以保证没有重复的排列。最后,我们遍历Set即可

### DFS算法生成全排列 #### 背景介绍 深度优先搜索(Depth First Search, DFS)是一种用于遍历或搜索树或图的算法。它沿着树的深度遍历节点,尽可能深地探索每条分支[^1]。 对于全排列问题,可以通过DFS来枚举所有的可能组合。具体来说,可以利用递归来实现这一过程,在每一层递归中尝试将当前未使用的元素加入到已有的序列中,并继续向下一层递归直到完成整个排列。 #### 实现方法 以下是基于C++语言的一个标准实现方式: ```cpp #include <iostream> #include <vector> using namespace std; void dfs(vector<int>& path, vector<bool>& used, int n) { if (path.size() == n) { // 当前路径长度等于n时输出结果 for(auto num : path){ cout << num << " "; } cout << endl; return; } for(int i = 1; i <= n; ++i){ // 尝试每一个数作为下一个位置的选择 if(!used[i]){ // 如果该数尚未被使用过,则将其加入路径并标记为已使用 path.push_back(i); used[i] = true; dfs(path, used, n); // 继续处理下一位 // 回溯操作:移除最后一个加入的数并将对应标志位重置为false以便后续其他情况能再次选用此数 path.pop_back(); used[i] = false; } } } int main(){ int m; cin >> m; vector<int> path; // 存储当前构建中的排列 vector<bool> used(m+1); // 记录哪些数字已经被选入排列 dfs(path, used, m); return 0; } ``` 上述代码定义了一个`dfs`函数用来执行实际的深度优先搜索逻辑。通过维护两个辅助结构——记录当前部分解的向量 `path` 表示各数值是否已被选取的状态数组 `used[]` ,实现了对所有可行排列方案的有效穷尽访问[^2]。 #### 关键点解析 - **终止条件**: 当已经选择了m个不同的整数形成完整的排列时停止进一步深入。 - **选择列表&约束条件**: 对于每个待定的位置考虑从剩余可用候选集中挑选合适的成员填充之;这里借助布尔型变量组`used[]`控制重复取舍行为的发生与否。 - **状态更新与撤销**: 进入更深一层之前修改现有状况反映新增加的信息;退出之后恢复原状允许别的可能性得以考察。 #### 总结 采用DFS策略解决全排列问题是经典而有效的手段之一。其核心在于合理设计递归框架以及妥善管理过程中涉及的各种数据结构以支持正确无误的操作流程展开。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值