leetcode題解-483. Smallest Good Base

題目:

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.

本題是尋找一個數最小的good base。其定義是對於一個數y,其x進製表示爲全1,則稱x是y的good base。應該比較好理解,其實就是將y寫成1+x+x^2+...+x^(n-1),就是一個等比數列求和,於是我們可以將其轉化爲y = (x^n - 1)/(x - 1),其中x>=2, 3<y<10^18,爲了尋找最小的x,我們可以先來確定一下n的取值範圍,很明顯x越小n越大,所以當x=2時,n最大爲log2(y+1)。從第三個例子可以看出來,當x=y-1時,n最小爲2。所以有了n的取值範圍我們就可以遍歷所有可能的n,然後每次循環中y和n都是確定值,在對x使用二叉搜索確定其值即可。

另外一個需要注意的問題就是,因爲本題中的數都比較大,所以要注意溢出問題,之前也做過一到這種題,可以使用java內置的BigInteger類進行處理。代碼如下所示:

    public static String smallestGoodBase(String n) {
        //現將字符串解析成long型數據
        long s = Long.parseLong(n);
        //對所有可能的指數n進行遍歷
        for(int max_e=(int)(Math.log(s)/Math.log(2)) + 1; max_e>=2; max_e--){
            long low=2, high=s, mid;
            //進行二叉搜索,尋找最小的good base。
            while(low <= high){
                mid = low + (high - low)/2;
                //一開始沒有使用BigInteger,會報錯
                BigInteger left = BigInteger.valueOf(mid);
                left = left.pow(max_e).subtract(BigInteger.ONE);
                BigInteger right = BigInteger.valueOf(s).multiply(BigInteger.valueOf(mid).subtract(BigInteger.ONE));
                int cmr = left.compareTo(right);
                if(cmr == 0)
                    return String.valueOf(mid);
                else if(cmr > 0)
                    high = mid - 1;
                else
                    low = mid + 1;
            }
        }
        return String.valueOf(s-1);
    }

上面這種方法效率比較低,還在網上找到了下面這種解決方案,首先說前面三行,一個是使用內置方法將字符串轉化爲long型整數,一個是寫循環,測試結果發現第二種效果更好==,其次使用這種方法可以擊敗98%的用戶,原因是其在二叉搜索的過程中的上限取的是Math.pow(num, 1.0/p) + 1,相比num本身小了很多,所以大大節省了時間。

    public String smallestGoodBase1(String n) {
        long num = 0;
        for (char c : n.toCharArray()) num = num * 10 + c - '0';
        //long num = Long.parseLong(n);
        long x = 1;
        for (int p = 64; p >= 1; p--) {
            if ((x << p) < num) {
                long k = helper(num, p);
                if (k != -1) return String.valueOf(k);
            }
        }
        return String.valueOf(num - 1);
    }

    private long helper(long num, int p) {
        long l = 1, r = (long)(Math.pow(num, 1.0/p) + 1);
        while (l < r) {
            long mid = l + (r - l) / 2;
            long sum = 0, cur = 1;
            for (int i = 0; i <= p; i++) {
                sum += cur;
                cur *= mid;
            }
            if (sum == num) return mid;
            else if (sum > num) r = mid;
            else l = mid + 1;
        }
        return -1;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章