猿问

给定一个数字 n,列出所有 n 位数字,使每个数字没有重复数字

我正在尝试解决以下问题。给定一个整数 n,列出所有 n 位数字,这样每个数字都没有重复的数字。


例如,如果 n 为 4,则输出如下:


0123

0124

0125

...

9875

9876

4 位数字的总数为 5040

我目前的方法是蛮力。我可以生成所有 n 位数字,然后使用 Set 列出所有没有重复数字的数字。但是,我很确定有一种更快、更好、更优雅的方法来做到这一点。


我在用 Java 编程,但我可以用 C 阅读源代码。


慕容3067478
浏览 347回答 3
3回答

慕码人8056858

在数学上,你有10个所述第一数量,选项9为第二,8为第三,和7的第4位。所以,10 * 9 * 8 * 7 = 5040。以编程方式,您可以使用一些组合逻辑生成这些。使用函数式方法通常会使代码更简洁;这意味着递归地构建一个新字符串,而不是尝试使用 StringBuilder 或数组来不断修改现有字符串。示例代码以下代码将生成排列,无需重复使用数字,无需任何额外的集合或映射/等。public class LockerNumberNoRepeats {&nbsp; &nbsp; public static void main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Total combinations = " + permutations(4));&nbsp; &nbsp; }&nbsp; &nbsp; public static int permutations(int targetLength) {&nbsp; &nbsp; &nbsp; &nbsp; return permutations("", "0123456789", targetLength);&nbsp; &nbsp; }&nbsp; &nbsp; private static int permutations(String c, String r, int targetLength) {&nbsp; &nbsp; &nbsp; &nbsp; if (c.length() == targetLength) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(c);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return 1;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; int sum = 0;&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i < r.length(); ++i) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sum += permutations(c + r.charAt(i), r.substring(0,i) + r.substring(i + 1), targetLength);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return sum;&nbsp; &nbsp; }}输出:...98759876Total combinations = 5040解释从@Rick 的评论中提取这一点,因为它说得很好,有助于澄清解决方案。所以为了解释这里发生的事情 - 它正在递归一个带有三个参数的函数:我们已经使用过的数字列表(我们正在构建的字符串 - c),我们还没有使用过的数字列表(字符串r) 和目标深度或长度。然后当一个数字被使用时,它被添加到 c 并从 r 中删除以供后续递归调用,因此您不需要检查它是否已经使用,因为您只传递那些尚未使用的数字。

海绵宝宝撒

回溯法也是一种蛮力法。private static int pickAndSet(byte[] used, int last) {&nbsp; &nbsp; if (last >= 0) used[last] = 0;&nbsp; &nbsp; int start = (last < 0) ? 0 : last + 1;&nbsp; &nbsp; for (int i = start; i < used.length; i++) {&nbsp; &nbsp; &nbsp; &nbsp; if (used[i] == 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; used[i] = 1;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return -1;}public static int get_series(int n) {&nbsp; &nbsp; if (n < 1 || n > 10) return 0;&nbsp; &nbsp; byte[] used = new byte[10];&nbsp; &nbsp; int[] result = new int[n];&nbsp; &nbsp; char[] output = new char[n];&nbsp; &nbsp; int idx = 0;&nbsp; &nbsp; boolean dirForward = true;&nbsp; &nbsp; int count = 0;&nbsp; &nbsp; while (true) {&nbsp; &nbsp; &nbsp; &nbsp; result[idx] = pickAndSet(used, dirForward ? -1 : result[idx]);&nbsp; &nbsp; if (result[idx] < 0) {&nbsp; //fail, should rewind.&nbsp; &nbsp; &nbsp; if (idx == 0) break;&nbsp; &nbsp; &nbsp; //the zero index rewind failed, think all over.&nbsp; &nbsp; &nbsp; dirForward = false;&nbsp; &nbsp; &nbsp; idx --;&nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; } else {//forward.&nbsp; &nbsp; &nbsp; &nbsp; dirForward = true;&nbsp; &nbsp; }&nbsp; &nbsp; idx ++;&nbsp; &nbsp; if (n == idx) {&nbsp; &nbsp; &nbsp; &nbsp; for (int k = 0; k < result.length; k++) output[k] = (char)('0' + result[k]);&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(output);&nbsp; &nbsp; &nbsp; &nbsp; count ++;&nbsp; &nbsp; &nbsp; &nbsp; dirForward = false;&nbsp; &nbsp; &nbsp; &nbsp; idx --;&nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return count;}

SMILET

注意这里的对称性:01230124...987598769876 = 9999 - 1239875 = 9999 - 124所以对于初学者来说,你可以把工作切成两半。您可能能够找到一个涵盖场景的正则表达式,例如,如果一个数字在同一字符串中出现两次,则它匹配/失败。正则表达式是否会更快,谁知道呢?特别是对于四位数字,您可以嵌套 For 循环:for (int i = 0; i < 10; i++) {&nbsp; &nbsp;for (int j = 0; j < 10; j++) {&nbsp; &nbsp; &nbsp; &nbsp;if (j != i) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for (int k = 0; k < 10; k++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ((k != j) && (k != i)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for (int m = 0; m < 10; m++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ((m != k) && (m != j) && (m != i)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;someStringCollection.add((((("" + i) + j) + k) + m));(等等)或者,对于更通用的解决方案,这是递归的方便性的一个很好的例子。例如,您有一个函数,它获取先前数字的列表和所需的深度,如果所需数字的数量小于深度,则只需进行十次迭代的循环(通过您要添加的数字的每个值),如果该数字已不存在于列表中,然后将其添加到列表中并递归。如果您处于正确的深度,只需连接列表中的所有数字并将其添加到您拥有的有效字符串集合中。
随时随地看视频慕课网APP

相关分类

Java
我要回答