前言
对于全排列问题,先将问题与转换为全排列问题,然后用DFS来模拟全排列。
一、Case
1、原题
A.题目
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
B.实例
示例 1:
输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
2、题解
该题的第一个问题就是,最大n位十进制数存储可能超过数值型的字节数,所以要用字符串来记录这些数值,所以可以使用全排列去组合所有可能的数值。
A.思想
B.Code and Annotation
package com.xhu.offer;
import java.util.Arrays;
/**
* 剑指offer第30天,分治算法
*/
public class DivideAlg {
/**
* leetcode不需要考虑大数问题。
* @param n
* @return
*/
public int[] printNumbers(int n) {
n = (int) Math.pow(10, n);
int[] res = new int[n - 1];
for (int i = 1; i < n; i++) {
res[i - 1] = i;
}
return res;
}
//每一次排列,用stringBuilder来组合一个字符串。
private StringBuilder sb = new StringBuilder();
//每一个排列好了,都用该字符串数据记录
private String[] res = null;
//关联上面的数组,用count来做下标,让数组正确将字符串记录
private int count = 0;
/**
* 考虑大数问题,即数越界
* Core:若要考虑大数问题,则需要字符串存储,所以可以使用全排列。即使用到递归去全排列。
*
* @param n
* @return
*/
public String[] printNumbers2(int n) {
//1.初始化记录数组,它的长度应为10的n次方 - 1
res = new String[(int) Math.pow(10, n) - 1];
//2.递归来完成全排列的过程。
dfs(n);
//3.返回记录满字符串的数组。
return res;
}
/**
* 递归来模拟全排列
*
* @param n n个数来进行全排列
*/
private void dfs(int n) {
//递归出口,当没有数来进行全排列时,则将字符串记录并结束此次递归。
if (n == 0) {
//因为0没有记录,所以全是0的情况就不考虑把其记录下来。
if (sb.length() > 0) res[count++] = sb.toString();
return;
}
//递归体,0-9来进行全排列
for (int i = 0; i <= 9; i++) {
//只有不是0开头的才append到后面。
if (i != 0 || sb.length() != 0) {
sb.append(i);
dfs(n - 1);
//每次回来都要去除上一次添加的。
sb.delete(sb.length() - 1, sb.length());
} else dfs(n - 1);//本身就没记录,所以不用考虑delete上一次的字符
}
}
/**
* 主函数验证算法
* @param args
*/
public static void main(String[] args) {
System.out.println(Arrays.toString(new DivideAlg().printNumbers2(2)));
}
}
总结
1)全排列问题 -> 全排列 -> dfs递归实现。
参考文献
[1] Leetcode原题
[2] 以上图片来自Leetcode用户的评论