难度:困难。
标签:数学,二分查找。
这个题,太绕了,浓浓的数学味,想不到方法。
没有看数学方法的解答,看了个比较容易想到的方法,但是也很绕,想不到一个条件就写不出来。
使用二分法进行解答。
- 给定n后,首先确定全为1的k进制串的最长长度,当为二进制数时,长度是最长的,因此最长度为 M a x L e n = l o g 2 n + 1 MaxLen=log_2n + 1 MaxLen=log2n+1
- 为了使k最小,则从最长长度MaxLen开始遍历,得到的第一个符合条件的就是k最小的情况。
确定了len后,确定k的范围,k的范围最小为2,最大满足 k ( l e n − 1 ) < x k^{(len-1)}<x k(len−1)<x,则最大k取 x ( 1 / ( i − 1 ) ) x^{(1/(i-1))} x(1/(i−1))。 - 确定k的范围后,使用二分法进行查找,get函数得到k进制,长度为len的进制串的大小(10进制表示)。
注意与n,k相关的都要使用unsigned long long类型。
正确解法:
class Solution {
// k^0 + k^1 + ... + k^(len - 1)
unsigned long long get(unsigned long long k, int len){
unsigned long long res = 1;
unsigned long long temp = 1;
for(int i = 1; i < len; ++i){
temp *= k;
res += temp;
}
return res;
}
public:
string smallestGoodBase(string n) {
unsigned long long x = stoull(n);
int max_len = log(x) / log(2) + 1;
for(int i = max_len; i >= 3; --i){
unsigned long long left = 2, right = (unsigned long long)pow(x, (double)1 / (i - 1));
while(left <= right){
unsigned long long mid = (left + right) / 2;
unsigned long long y = get(mid, i);
if(y == x)return to_string(mid);
else if(y > x)right = mid - 1;
else left = mid + 1;
}
}
return to_string(x - 1);
}
};
结果: