• leetcode1012


     1 # given number n, see whether n has repeated number
     2 def has_repeated(n):
     3     str_n = str(n)
     4     return len(set(str_n)) != len(str_n)
     5 
     6 def permutation(n, k):
     7     prod = 1
     8     for i in range(k):
     9         prod *= (n-i)
    10     return prod
    11 
    12 # calculate number of non-repeated n-digit numbers
    13 # note: the n-digit number can't start with 0
    14 # i.e: n_digit_no_repeat(2) calculates the non-repeated
    15 #   numbers in range [10, 99] (inclusive)
    16 def n_digit_no_repeat(n):
    17     if n == 1:
    18         return 9
    19     else:
    20         return  9 * permutation(9, n-1)
    21 
    22 class Solution(object):
    23     def numDupDigitsAtMostN(self, N):
    24         """
    25         :type N: int
    26         :rtype: int
    27         """        
    28         N_str = str(N)
    29         n_digit = len(N_str)
    30         digits = list(map(int, N_str))
    31         result = N - 1
    32         prefix = 0
    33         for i in range(1, n_digit):
    34             result -= n_digit_no_repeat(i)
    35         for i in range(n_digit):
    36             # when we fix the most significant digit, it 
    37             # can't be zero
    38             start = 0 if i else 1
    39             for j in range(start, digits[i]):
    40                 if has_repeated(prefix * 10 + j):
    41                     continue
    42                 if i != n_digit-1:
    43                     result -= permutation(10-i-1, n_digit-1-i)
    44                 else:
    45                     # optmized from `result -= has_repeated(prefix*10+j)`
    46                     result -= 1
    47             prefix = prefix*10 + digits[i]
    48         return result + has_repeated(N)

    参考:https://leetcode.com/problems/numbers-with-repeated-digits/discuss/256866/Python-O(logN)-solution-with-clear-explanation

    以下分析过程是我自己的思路,和上面的代码思路不太一样,具体的实现过程稍后补充,先把我的分析过程记录下来。

    1位(0~9)有0个

    2位(10~99)有9个:11,22,33,44,55,66,77,88,99

    3位(100~999)有252个

    百位以1~9开头,因为对于100~199的情况和200~299的情况都是一样的,因此外层用9相乘。

      以100~199为例:

      1.首先要找的个位和十位一样的:00,11,22,33,44,55,66,77,88,99,共10个。

      2.找个位和百位一样的:01,11,21,31,41,51,61,71,81,91,共10-1=9个。

      3.找十位和百位一样的:10,11,12,13,14,15,16,17,18,19,共10-1=9个。

    但是2步中出现了数字11,3步中也出现了数字11,因此每一轮是10 + (10-1) + (10-1) = 28个,

    因此外层9*28=252。

    4位(1000~9999):有4464个

    百位和千位单独考虑,是10~99:有9组包含重数字:11**,22**,33**,44**,55**,66**,77**,88**,99**。

    这9组数字,因为前缀已经是重数,因此后面的**无论是多少都满足要求,这样就得到了9*100=900个。

    接下来考虑10**~19**这10组,排除11**组之后,还剩9组。

    分析如下:以10**为例:

      1.首先找个位和十位一样的:00,11,22,33,44,55,66,77,88,99,共10个。

      2.找个位和百位0一样的:0010,20,30,40,50,60,70,80,90,共10-1=9个。

      3.找个位和千位1一样的:0111,21,31,41,51,61,71,81,91,共10-1=9个。

      4.找十位和百位0一样的:0001,02,03,04,05,06,07,08,09,共10-2=8个。

      5.找十位和千位1一样的:1011,12,13,14,15,16,17,18,19,共10-2=8个。

    可以看到有重复计算的数字,因此第2步的00在第1步已经出现过,因此第2步是9个;

    第3步有1个重复数字,剩下9个。第4步有2个重复数字,剩下8个,第5步有2个重复数字,剩下8个。

    根据上面的分析可以知道,每一组有10 + (10-1) + (10-1) + (10-2) + (10-2)=44个。

    因此从1000~1999这1000个数字中,有9*44=396个。再加上11**的100个,这样就是496个。

    那么同样的计算方式,可以知道2000~2999也是496,从1000~9999一共就是9*496=4464个。

    1位:9*0=0

    2位:9*1=9

    3位:9*(10+(10-1)*1+(10-1)*1)=252

    4位:9*(9*(10+(10-1)*2+(10-2)*2)+1*100)=4464

    5位:9*(9*(8*(10+(10-1)*3+(10-3)*3)+2*100)+1*1000)=62784 

    6位:9*(9*(8*(7*(10+(10-1)*4+(10-4)*4)+3*100)+2*1000)+1*10000)=763920

    7位:9*(9*(8*(7*(6*(10+(10-1)*5+(10-5)*5)+4*100)+3*1000)+2*10000)+1*100000)=8455680

    8位:9*(9*(8*(7*(6*(5*(10+(10-1)*6+(10-6)*6)+5*100)+4*1000)+3*10000)+2*100000)+1*1000000)=88367040

    9位:9*(9*(8*(7*(6*(5*(4*(10+(10-1)*7+(10-7)*7)+6*100)+5*1000)+4*10000)+3*100000)+2*1000000)+1*10000000)=896734080

    10位:9*(9*(8*(7*(6*(5*(4*(3*(10+(10-1)*8+(10-8)*8)+7*100)+6*1000)+5*10000)+4*100000)+3*1000000)+2*10000000 )+1*100000000)=8996734080

    10位以上,最内部的计算式子10+(10-1)*9+(10-9)*9=100,也就表示任意的数字都包含重复。

    经过以上的分析,可以得到如下的递推公式:x表示数字的位数,例如x=3表示100~999之间的满足要求的数字个数(不含0~99之间的)

     1 k=[9,8,7,6,5,4,3]
     2 for x in range(3,11):
     3     c = x - 4
     4     he = (10+(10-1)*(x-2)+(10-(x-2))*(x-2))
     5     p = 2
     6     while c >= 0:
     7         he = k[c] * he + (c+1) * pow(10,p)
     8         c -= 1
     9         p += 1
    10     y = he * 9
    11     print(y)
    12 '''
    13 252
    14 4464
    15 62784
    16 763920
    17 8455680
    18 88367040
    19 896734080
    20 8996734080
    21 '''

    我尝试用这个思路来做一个完整的解决方案,如果能完成,我会代码补充上。如果做不出来,就算了吧,哈哈。

    leetcode上面的hard题目,如果自己有思路就尝试着写一下,如果没有思路就学习别人的。

    算法的能力的提升,是一个循序渐进的过程,急不得。

  • 相关阅读:
    利用Powerdesigner16.5(64位)连接64位oracle 配置系统odbc驱动
    Commons BeanUtils 中对Map的操作
    java内存模型与线程
    类加载器详解
    虚拟机性能监控与故障处理工具
    ENode框架Conference案例分析系列之
    ENode框架Conference案例分析系列之
    225.优化路径选择
    224.CAD相关操作
    223.概率统计
  • 原文地址:https://www.cnblogs.com/asenyang/p/10548480.html
Copyright © 2020-2023  润新知