1012. Numbers With Repeated Digits
挺有难度又挺好的一道题。计算 with repeated digits 的数字比较麻烦,直接做的话会 trapped in the puzzle of various cases. 不如直接计算 without repeated digits 的数字(which can be easily converted to a permutation problem),然后拿N减去,就得到答案了。
这样的话,对于一个 K 位的数,就只需要分两部分解决问题:
位数 < K时有多少数字 without repeated digits(取值不设限)?
位数 == K时有多少数字 without repeated digits (取值时需要让最后合成数 <= N)?
So the basic idea is, say we have a number 314159. We somehow turn it into [3,1,4,1,5,9]. Then we r going to do a lot of divide-and-conquers.
Divide-and-Conquer 1.You probably already noticed if the the problem is "Count the Number Without Repeated Digit for in any number LESS THAN N=100 or 1000 or 10000 (any power of 10)". It is a relatively easier question. for N=100, the answer is 100- (9*8+9) . For N=1000, the answer is 1000 - (9*8*7 + 9*8 + 9)
Divide-and-Conquer 2.Our real question has two aspects different from above. One, it is not asking less than LESS THAN '<', but is asking '<='. Two, N is something like 314159, not a power of 10. Since we can take care of numbers < 100000 as in Divide-and-Conquer 1, we only need to worry about 100000 - 314259.
Now we basically need to loop through [3,1,4,2,5,9] to find all the digit-unique 6-place numbers. Each time we are visiting ith place, the logic has 3 different variations.
2.a. If we are visiting 3 (first place), we need to visit 1,2. We are actually asking the question 'how many digit-unique 6-place numbers with leading 1 or 2?'. Well, why not 0? 0 has been calculated through 'Divide-and-Conquer 1'
2.b. If we are visiting 1-5 (2nd to 5th place), we need to visit any UNUSED values in 0 to (val-1). For example, if we are visiting 4 (3rd place), we are essentially answering this question: how many 31xxxx are digit-unique 6-place numbers? We need to try 310xxx 311xxx(No! 1 is USED) 312xxx 313xxx(No!3 is USED)
2.c. If we are visiting 9 (last place), we need to visit any UNUSED values in 0 to val. Why val not val-1? Because you need val to cover the exact case of 314259. (This iteration we are testing out 31425x).
为了解决 2.c 中的问题,我们在生成 digits 数组的时候,把最后一位加了1,这个padding操作可以 cover 掉最后一位数取值不设限的问题。
(事实上,直接把N+1也可以通过,但我自己没想通为什么,这样对于 999 这样的数字会改变K。)
class Solution:
def numDupDigitsAtMostN(self, N: int) -> int:
def factorial(n):
return n * factorial(n-1) if n > 1 else n
# pick m out of n, ordred matters
def permutation(m, n): return factorial(n) // factorial(n - m)
# get the digits information
digits = [int(d) for d in str(N)]
# padding the last digit to cover its all cases
digits[-1] += 1
K = len(nums) # N has K digits
cnt = 0 # number with no repeated val
# count all **postive non-digit-repeating number with less than K digits
for i in range(1, K):
cnt += 9 * P(i-1, 9)
# count non-digit-repeating number number with K digits
for i in range(K):
# prefix = nums[:i] + currentDigit
# currentDigit < nums[i]
for x in range(1 if i == 0 else 0, nums[i]):
if x in digits[:i]:
continue # avoid duplication
cnt += P(K - (i + 1), 10 - (i + 1))
# if current digit has already appeared in the former
# any later case is invalid (has repeated digits)
# so we don't need to keep going
if digits[i] in digits[:i]: break
return N - cnt
Last updated
Was this helpful?