一起刷力扣之【357. 统计各位数字都不同的数字个数】

152 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

题目描述

给你一个整数 n ,统计并返回各位数字都不同的数字 x 的个数,其中 0 <= x < 10n^n 。

示例

输入: n = 2
输出: 91
解释: 答案应为除去 11、22、33、44、55、66、77、88、99 外,在 0 ≤ x < 100 范围内的所有数字。 
输入: n = 0
输出: 1

提示

  • 0 <= n <= 8

数学

我们可以将数值n理解为一个数值的长度,该长度每增加一位,相当于我们新增多一层区间[0-9]for循环,将其与前面的结果集进行拼接。

同时,由于题目要求的是统计各位数都不同的数字,那么数值新增的每一位,都需要与前面所有位数的数字不同,模拟代码如下所示:

public static void main(String[] args) {
    for (int one = 0; one < 10; one++) {
        for (int two = 0; two < 10; two++) {
            if (two == one) {
                continue;
            }
            for (int three = 0; three < 10; three++) {
                if (three == one || three == two) {
                    continue;
                }
                for (int four = 0; four < 10; four++) {
                    if (four == one || four == two || four == three) {
                        continue;
                    }
                    for (int five = 0; five < 10; five++) {
                        if (five == one || five == two || five == three || five == four) {
                            continue;
                        }
                        for (int six = 0; six < 10; six++) {
                            if (six == one || six == two || six == three || six == four || six == five) {
                                continue;
                            }
                            for (int seven = 0; seven < 10; seven++) {
                                if (seven == one || seven == two || seven == three || seven == four || seven == five || seven == six) {
                                    continue;
                                }
                                for (int eight = 0; eight < 10; eight++) {
                                    if (eight == one || eight == two || eight == three || eight == four || eight == five || eight == six || eight == seven) {
                                        continue;
                                    }
                                    System.out.println("" + one + two + three + four + five + six + seven + eight);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

上面的代码太冗余了,有多个重复的步骤,我们可以以这个为基础,将重复的步骤抽离,优化。

例如:当n == 2的时候,我们新增的那些数字需要排除掉与n == 1时已有的数字,当n == 3的时候,我们新增的那些数字需要排除掉与n == 2时已有的数字,以此类推。

区间[0,9]有10个数字,每增加一位,我们计算的时候则相对的也要把需要排除的范围增加一位。

class Solution {
    public int countNumbersWithUniqueDigits(int n) {
        // 边界处理
        if(0 == n){
            return 1;
        }

        // n == 2时,需要去除的元素为9个,设基数为9
        int count = 9, res = 10;
        for(int i = 1; i < n; ++i){
            // 基数 * 后续增加的范围数
            count *= 10 - i;
            // 结果累加
            res += count;
        }

        return res;
    }
}