0483. 最小好进制
大约 2 分钟
---
0483. 最小好进制
- 标签:数学、二分查找
- 难度:困难
题目链接
题目大意
描述:
以字符串的形式给出 。
要求:
以字符串的形式返回 的最小「好进制」。
说明:
- 好进制:如果 的 进制数的所有数位全为 ,则称 是 的一个「好进制」。
- 的取值范围是 。
- 没有前导 。
示例:
- 示例 1:
输入:n = "13"
输出:"3"
解释:13 的 3 进制是 111。- 示例 2:
输入:n = "4681"
输出:"8"
解释:4681 的 8 进制是 11111。解题思路
思路 1:数学 + 二分查找
核心思想:如果 的 进制表示为全 ,那么 ,即 。我们需要找到最小的 使得该等式成立。
算法步骤:
- 枚举进制表示的长度 :取值范围为 (因为 ,最多有 位)。
- 二分查找进制 :对于每个固定的长度 ,二分查找满足条件的进制 。
- 左边界 (进制至少为 )。
- 右边界 (最大进制值)。
- 在区间 中二分查找 。
- 验证等式:判断 是否满足 。
- 返回最小 :找到满足条件的 后返回。
注意:需要考虑边界情况,如 的特殊情况。
思路 1:代码
class Solution:
def smallestGoodBase(self, n: str) -> str:
n_num = int(n)
# 枚举进制表示的长度 m(从大到小,找到的第一个即为最小的 k)
max_len = len(bin(n_num)) - 2 # n 的二进制表示长度
for m in range(max_len, 0, -1):
# 二分查找进制 k
left, right = 2, n_num - 1
while left <= right:
k = (left + right) // 2
# 计算 k^0 + k^1 + ... + k^m 的和
s = 0
current = 1 # k^0
for i in range(m + 1):
s += current
# 检查是否溢出
if s > n_num:
break
if i < m:
current *= k
# 提前检查是否会溢出
if current > n_num:
s = n_num + 1 # 标记溢出
break
if s == n_num:
return str(k)
elif s < n_num:
left = k + 1
else:
right = k - 1
# 如果没找到,返回 n - 1(此时 k = n - 1 一定满足条件)
return str(n_num - 1)思路 1:复杂度分析
- 时间复杂度:。其中 是给定的数字。外层枚举长度 的复杂度为 ,内层二分查找的复杂度为 ,每次验证计算等比数列和的复杂度为 ,因此总的时间复杂度为 。
- 空间复杂度:。只使用了常数个额外变量。