483-Smallest Good Base

本文介绍了一种算法,用于寻找一个整数n的最小好进制k,使得n在该进制下所有位均为1。通过数学推导确定了进制k与位数m的有效搜索范围,并使用二分查找提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description:

For an integer n, we call k>=2 a good base of n, if all digits of n base k are 1.

Now given a string representing n, you should return the smallest good base of n in string format.


Example 1:

Input: "13"
Output: "3"
Explanation: 13 base 3 is 111.

Example 2:

Input: "4681"
Output: "8"
Explanation: 4681 base 8 is 11111.

Example 3:

Input: "1000000000000000000"
Output: "999999999999999999"
Explanation: 1000000000000000000 base 999999999999999999 is 11.

Note:
1.The range of n is [3, 10^18].
2,The string representing n is always valid and will not have leading zeros.


问题描述:

对于n来说,如果一个大于等于2的进制k,能让n以k进制表示后每一位都是1,那么称k为一个好的进制
现在给定n,你需要返回最小的好的进制k

例子:
输入为”13”
输出为”3”
解释:13以3进制表示为111


问题分析:

令进制为k,我们知道n可以表示为:
n=k0+k1+k2+....km1=km1k1n=k0+k1+k2+....km−1=km−1k−1

于是我们可以将n表示为形如f(k,m)f(k,m)的函数,我们知道k和m是成反比的关系,当f(k1,m1)=f(k2,m2),m1>m2,k1<k2f(k1,m1)=f(k2,m2),若m1>m2,那么必有k1<k2,利用这个性质,我们可以由大到小遍历m,当m固定时,若能找到一个合适的k使得f(k,m)=nf(k,m)=n,那么k即是最小的解。现在虽然我们还不知道k的取值范围,不过在一个范围内找到一个满足条件的数,二分查找。

于是现在问题化作,如何找到m和k的范围.

  1. m的范围
    由k和m成反比,当k等于2时,m最大,即2m1=n2m−1=n,得m<=log(n+1)m<=log⁡(n+1)
    于是得到2<=m<=log(n+1)(m1)2<=m<=log⁡(n+1)(注意m不能为1)
  2. k的范围
    n=k0+k1+k2+....km1=km1k1n=k0+k1+k2+....km−1=km−1k−1,得
    n<km1n<km−1,得到k>(n+1)1mk>(n+1)1m
    n=k0+k1+k2+....km1=km1k1n=k0+k1+k2+....km−1=km−1k−1,得
    n>=km1n>=km−1,得到k<=n1m1k<=n1m−1

解法:

/*
如果想看更加完整和详细的解释,可以看看这篇链接:
https://leetcode.com/problems/smallest-good-base/discuss/96591/Java-O((logn)2)-binary-search-solution
*/
class Solution {
    public String smallestGoodBase(String n) {
        long num = Long.valueOf(n);

        for(int m = (int)(Math.log(num + 1) / Math.log(2));m >= 2;m--){
            //k的下界和上界
            long l = (long)Math.pow(num + 1, 1.0 / m);
            long r = (long)Math.pow(num, 1.0 / (m - 1));
            //二分查找,一旦找到合适的k,k为最小解
            while(l <= r){
                long k = l + ((r - l) >> 1);
                long f = 0L;
                for(int i = 0;i < m;i++, f = f * k + 1);
                if(num == f){
                    return String.valueOf(k);
                }else if(num > f){
                    l = k + 1;
                }else{
                    r = k - 1;
                }
            }
        }
        //注意,我们始终有k = num - 1,m = 2的解决方案
        return String.valueOf(num - 1);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值