今天写了这道题才明白递归搜索树的含义

从 1∼n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。

输入格式
两个整数 n,m ,在同一行用空格隔开。

输出格式
按照从小到大的顺序输出所有方案,每行 1 个。

首先,同一行内的数升序排列,相邻两个数用一个空格隔开。

其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。

数据范围
n>0 ,
0≤m≤n ,
n+(n−m)≤25
输入样例:
5 3
输出样例:
1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5 
思考题:如果要求使用非递归方法,该怎么做呢?

首先看这道题,一样熟悉的题目,只不过变成挑选m个数字出来。

最初的版本

import java.util.*;

public class Main{
    static int N = 30;
    static int n;
    static int m;
    static int[] st = new int[N];
    static boolean[] vis = new boolean[N];
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        dfs(0);
    }

    public static void dfs(int u){
        //u表示你在第几层,同时也表示你在填第几个空
        //比如第0层,默认为0
        //在第一层时,你挑选哪个来填第一个空
        if(u == m){
            for(int i = 0; i < m; i++){
                System.out.printf("%d ",st[i]);
            }
            System.out.println();
            return;
        }
        //i从1开始,所以每次递归进去的时候都会从首位开始找,如果被使用过了,就跳到下一个数
        //所以就没有思考有没有升序的思考
        for(int i = 1; i <= n; i++){
            if(!vis[i]){
                st[u] = i;
                vis[i] = true;
                dfs(u + 1);
                vis[i] = false;   
            }
        }
    }
}

一开始没有考虑到升序的问题,所以就造成跟之前排列相似,u表示的层数,

递归_字典序

然后我就想,如果要考虑升序的话,也就是说你每次递归进来的时候,都要根据上一个选的数字来挑选下一个数

比如你在2层的时候,在挑选第三个数时,我们用1 3 _举例,当我们选完3时,我们为了升序肯定是不能选2的,所以这里我有两种思路

一种是你可以继续遍历2,但是得加个条件,就是上一个数要大于当前数才行,但这样会浪费一次判断

另一种是类似剪枝的思想,就是你保存上一个的状态值 + 1,在下一个递归时,就从那个位置开始遍历,这样就可以了

import java.util.*;
/**
 *写了这道题才开始理解的递归的含义
 * 首先是
 * 
 * 
 * 
 * 
 */
public class Main{
    static int N = 30;
    static int n;
    static int m;
    static int[] st = new int[N];
    static boolean[] vis = new boolean[N];
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        dfs(0,1);
    }
    
    public static void dfs(int u,int start){
        if(u == m){
            for(int i = 0; i < m; i++){
                System.out.printf("%d ",st[i]);
            }
            System.out.println();
            return ;
        }
        
        for(int i = start; i <= n; i++){
            if(!vis[i]){
                st[u] = i;
                vis[i] = true;
                //保存此时选的数字
                dfs(u + 1,i + 1);
                vis[i] = false;
                
            }
        }
    }
}