leetcode -- 357. Count Numbers with Unique Digits 【数学表达 + 递推 + 破坏递推的情况的排除+回溯】

来源:互联网 发布:暨南大学网络教学平台 编辑:程序博客网 时间:2024/06/11 01:01

题目

Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < 10n.

Example:
Given n = 2, return 91. (The answer should be the total numbers in the range of 0 ≤ x < 100, excluding[11,22,33,44,55,66,77,88,99])

题意理解

给定一个非负整数n , 计算不含有重复数字的整数 x 的个数,其中 0 <= x <= 10^n.

分析及解答

解答1:(递推)

分析:

  • 数学表达】将问题通过数学方式精确定义出来,量化不同规模的n之间可能存在的关系。这里指 f(n) 和 f(n-1)之间的关系。
  • 异常排除】有些特殊情况会阻止后面的递推,想办法将其排除。这里指首字母为0的情况。
  • 递推表达】将不同规模的数据表达成递推的形式,能够节省计算量
  • 回溯】该问题也可以用回溯解答,只不过我们将剪支的过程人工识别了,节省了计算机的工作量。

Following the hint. Let f(n) = count of number with unique digits of length n.

f(1) = 10. (0, 1, 2, 3, ...., 9)

f(2) = 9 * 9. Because for each number i from 1, ..., 9, we can pick j to form a 2-digit number ij and there are 9 numbers that are different from i for j to choose from.(排除了特殊情况0

f(3) = f(2) * 8 = 9 * 9 * 8. Because for each number with unique digits of length 2, say ij, we can pick k to form a 3 digit number ijk and there are 8 numbers that are different from i and j for k to choose from.

Similarly f(4) = f(3) * 7 = 9 * 9 * 8 * 7....

...

f(10) = 9 * 9 * 8 * 7 * 6 * ... * 1

f(11) = 0 = f(12) = f(13)....

any number with length > 10 couldn't be unique digits number.

The problem is asking for numbers from 0 to 10^n. Hence return f(1) + f(2) + .. + f(n)

As @4acreg suggests, There are only 11 different ans. You can create a lookup table for it. This problem is O(1) in essence.


 public int countNumbersWithUniqueDigits(int n) {        if (n == 0)     return 1;                int res = 10;        int uniqueDigits = 9;        int availableNumber = 9;        while (n-- > 1 && availableNumber > 0) {            uniqueDigits = uniqueDigits * availableNumber;            res += uniqueDigits;            availableNumber--;        }        return res;    }

答案来自:(https://discuss.leetcode.com/topic/47983/java-dp-o-1-solution)

解答2(回溯):

分析:

  • 状态记录的数据结构】下面算法比较巧妙的地方,通过bool 数组记录状态,因为状态位有限(0 - 9),所以用数组表示是一个不错的选择,这样可以有效利用数组的查询速度(O(1))
  • 回溯递归  + 对于回退的限制(关键)。通过下面算法可以体会回溯的含义。

The idea is to append one digit at a time recursively (only append digits that has not been appended before). Number zero is a special case, because we don't want to deal with the leading zero, so it is counted separately at the beginning of the program. The running time for this program is O(10!) worst case, or O(n!) if n < 10.

public class Solution {public static int countNumbersWithUniqueDigits(int n) {if (n > 10) {return countNumbersWithUniqueDigits(10);}int count = 1; // x == 0long max = (long) Math.pow(10, n);boolean[] used = new boolean[10];for (int i = 1; i < 10; i++) {used[i] = true;count += search(i, max, used);used[i] = false;}return count;}private static int search(long prev, long max, boolean[] used) {int count = 0;if (prev < max) {count += 1;} else {return count;}for (int i = 0; i < 10; i++) {if (!used[i]) {used[i] = true;long cur = 10 * prev + i;count += search(cur, max, used);used[i] = false;}}return count;}}



阅读全文
0 0