目录

LC 902. 最大为 N 的数字组合 (opens new window) (opens new window)

困难

# 问题描述

给定一个按 非递减顺序 排列的数字数组 digits。你可以用任意次数 digits[i] 来写的数字。例如,如果 digits = ['1','3','5'],我们可以写数字,如 '13','551', 和 '1351315'

返回 可以生成的小于或等于给定整数 n 的正整数的个数

示例 1:

输入:digits = ["1","3","5","7"], n = 100
输出:20
解释:
可写出的 20 个数字是:
1, 3, 5, 7, 11, 13, 15, 17, 31, 33, 35, 37, 51, 53, 55, 57, 71, 73, 75, 77.

示例 2:

输入:digits = ["1","4","9"], n = 1000000000
输出:29523
解释:
我们可以写 3 个一位数字,9 个两位数字,27 个三位数字,
81 个四位数字,243 个五位数字,729 个六位数字,
2187 个七位数字,6561 个八位数字和 19683 个九位数字。
总共,可以使用 D 中的数字写出 29523 个整数。

示例 3:

输入:digits = ["7"], n = 8
输出:1

提示:

  • 1 <= digits.length <= 9
  • digits[i].length == 1
  • digits[i] 是从 '1''9' 的数
  • digits 中的所有值都 不同
  • digits非递减顺序 排列
  • 1 <= n <= 109

# 数学

可以分成位数小于指定数字和位数等于指定数字两种情况:

  • 当位数小于给出数字的位数时,可以生成的数字数量为可选数字的全排列。
  • 当位数等于给出数字的位数时,可以分成两种情况:
    • 当前位数对应的数字小于指定数字的对应位数的数字时,后续可以生成的数量为后面位数的全排列。
    • 当前位数对应的数字等于指定数字的对应位数的数字时,后一个数可选小于指定数字的对应位数的数字。

对于情况二,可以使用深度优先搜索进行查找,最终结果为两种情况之和。

/**
 * @param {string[]} digits
 * @param {number} n
 * @return {number}
 */
var atMostNGivenDigitSet = function (digits, n) {
  const sn = n.toString()
  const N = digits.length
  const K = sn.length
  let ans = 0
  for (let i = 1; i < K; i++) {
    ans += Math.pow(N, i)
  }
  const dfs = (len, isLess) => {
    if (len === K) return 1
    if (isLess) {
      return Math.pow(N, K - len)
    }
    let cnt = 0
    for (const digit of digits) {
      if (digit > sn[len]) break
      if (digit < sn[len]) {
        cnt += dfs(len + 1, true)
      } else {
        cnt += dfs(len + 1, false)
      }
    }
    return cnt
  }
  return ans + dfs(0, false)
}
  • 时间复杂度:O(logn×k)O(\log{n} \times k),其中 nn 为给定数字,kk 表示给定的数字的种类。
  • 空间复杂度:O(logn)O(\log{n})
上次更新: 2023/01/31 19:48:05

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 , 转载请注明出处!