您可以在O(log(a)) 中通过对已排序“列表”应用二进制搜索来找到等于 1 的最后一个元素。
列表是隐喻的,其中的每个元素都是在通过简单计算查询时即时计算出来的:
list[i] = 1 n % a^i == 0
0 otherwise
您可以先使用指数找到可能的a 的范围:
curr = b
tempA = 1
while n % curr == 0:
curr = curr * curr
tempA = tempA *2
然后,在[tempA/2, tempA] 范围内运行二进制搜索。这个范围的大小是(a/2),所以找到符号列表1 中的最后一个“元素” - 在O(loga) 乘法中完成。
代码+演示:
private static int specialBinarySearch(int n, int b, int aLow, int aHigh) {
if (aHigh == aLow) return aHigh;
int mid = (aHigh - aLow)/2 + aLow;
//pow method can be optimized to remember pre-calculated values and use them
int curr = (int)Math.round(Math.pow(b, mid));
if (n % curr == 0) { //2nd half, or found it:
if (n % (curr*b) != 0) return mid; //found it
return specialBinarySearch(n, b, mid+1, aHigh); //2nd half
}
else return specialBinarySearch(n, b, aLow, mid); //first half
}
public static int findA(int n, int b) {
int curr = b;
int tempA = 1;
while (n % curr == 0) {
curr = curr * curr;
tempA = tempA *2;
}
return specialBinarySearch(n, b, tempA/2, tempA);
}
public static void main(String args[]) {
System.out.println(findA(62,2)); //1
System.out.println(findA(1024,2)); //10
System.out.println(findA(1,2)); //0
System.out.println(findA(100,2)); //2
System.out.println(findA(6804,3)); //5
}