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:
- The range of n is [3, 10^18].
- The string representing n is always valid and will not have leading zeros.
Subscribe to see which companies asked this question.
给定一个数num,求一个最小的基数,使得n以这个数为基的表示形式是“11....1“。想法是对“11..1”(n个1),对每个n,找出能使“11..1”(n个1)等于num的基,找基可以使用二分法。n应该从大到小,这样可以及早找出最小的符合要求的基,直接返回。这里num的范围是[3, 10^18],用unsigned long long能完全表示,所以n(1的个数)的范围是2到64,对于给定的数,还能跳过比较大的不可能的n,如果"10...0"(n-1个0)大于等于num,就不可能找到合适的基。二分搜索的范围也可以缩小,左端是2,右端是pow(num, 1.0/(n-1)) + 1,因为最高位是base^(n-1)。、
代码:
class Solution
{
public:
using ull = unsigned long long;
string smallestGoodBase(string n)
{
ull num = (ull)stoll(n);
for(int i = 63; i >= 1; --i)
{
if(((ull)(1) << i) >= num) continue;
ull ret = solve(num, i+1);
if(ret != 0) return to_string(ret);
}
return to_string(num - 1);
}
private:
int solve(ull num, int n)
{
int l = 2, r = (int)(pow(num, 1.0/(n-1)) + 1);
//cout << n << " " << r << endl;
while(l <= r)
{
int mid = (r - l) / 2 + l, ret = cmp(num, mid, n);
if(ret == 0) return mid;
else if(ret < 0)
{
l = mid + 1;
}
else
{
r = mid - 1;
}
}
return 0;
}
int cmp(ull num, ull base, int n)
{
ull sum = 0, d = 1;
while( --n >= 0)
{
sum += d;
if(sum > num) return 1;
d *= base;
}
return sum == num ? 0 : -1;
}
};