简体   繁体   中英

Convert algorithm from o(n) to o(1)

Basically what I wanted to is if a number n is divisible by b for a (count) times, then find the a (count), and divide n by b for a (count) times.

That is,

count = 0;
while(n%b == 0)
    n=n/b;
    count = count + 1;

How to optimize this, so that everything can be obtained in one step

You can do it in O(log(a)) by applying binary search, on a sorted "list" to find the last element that equals 1.

The list is metaphoric, and each element in it is calculated on the fly when queried by a simple calculation:

list[i] = 1      n % a^i == 0
          0      otherwise

You can first find the range of possible a 's using exponention:

curr = b
tempA = 1
while n % curr == 0:
    curr = curr  * curr
    tempA = tempA *2

And then, run the binary search on the range [tempA/2, tempA] . This range is of size (a/2) , so finding the last "element" that the symbolic list holds 1 - is done in O(loga) multiplications.

Code + Demo:

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

}

You cannot solve this in O(1) but there is a different kind of approach to this problem if you start using a numeric system where b is the base.

For example, if we have a number like 154200, and b is 10, we know the answer is 2 here immediately because we can simply count how many zeros there are on the right hand side.

Similarly, in binary, if b is 2, you simply count how many zeros there are on the right side with a binary representation.

If b is 5, we have to use the odd base 5 representation where a number like 8 is represented as 13. Again we know that the answer for a is zero is n=8 and b=5 because there are no zeros on the right hand side.

This won't necessarily give you speed gains except possibly in cases where b is a power of two where you can use bitwise logic to deduce the answer, but it gives you a different kind of way of looking at the problem lexically by digits instead of through arithmetic.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM