1. 程式人生 > 其它 >Leetcode小白試煉(20201207 連線連續二進位制數字)

Leetcode小白試煉(20201207 連線連續二進位制數字)

技術標籤:演算法程式設計學習字串演算法javaleetcode

文章目錄

一、題目

1. 題目描述

給你一個整數 n ,請你將 1 到 n 的二進位制表示連線起來,並返回連線結果對應的 十進位制 數字對 109 + 7 取餘的結果。
提示:
1 ≤ n ≤ 1 0 5 1 \leq n \leq10^5

1n105

2. 示例

示例1:
輸入:n = 1
輸出:1
解釋:二進位制的 “1” 對應著十進位制的 1 。
示例2:
輸入:n = 3
輸出:27
解釋:二進位制下,1,2 和 3 分別對應 “1” ,“10” 和 “11” 。
將它們依次連線,我們得到 “11011” ,對應著十進位制的 27 。

示例3:
輸入:n = 12
輸出:505379714
解釋:連線結果為 “1101110010111011110001001101010111100” 。
對應的十進位制數字為 118505380540 。
對 109 + 7 取餘後,結果為 505379714 。

3. 題目解析

按照題意,很容易想到先將範圍內的十進位制數轉換為二進位制,拼接後,再將這一串二進位制轉換為十進位制。但是要拼接的太長,使用此方法會超時。

二、個人解法

1. 解法分析

  • 使用StringBuffer來拼接存放所有數字的二進位制。
  • 使用long型別的result變數來儲存十進位制結果。
  • 從後往前取二進位制字串中的每一位,轉換為十進位制,累加至result,只要超過限制值就執行取餘操作。
  • 將result轉換為int型別,即為所求。

2. 程式碼

    /**
     * 第一次嘗試用Stringbuffer拼接從1到n的二進位制,然後逐位求解,超出時間限制
     *
     * @param n
     * @return
     */
    public int concatenatedBinary1(int n) {
        StringBuffer str1 =
new StringBuffer(); // 用StringBuffer的append方法將範圍內的整數轉換的二進位制拼接 for (int i = 1; i <= n; i++) { // Integer.toBinaryString方法可以將十進位制轉換為二進位制字串 str1.append(Integer.toBinaryString(i)); } double result = 0; int j = 0; // 取二進位制的每一位,轉換成10進位制 for (int i = str1.length() - 1; i >= 0; i--) { double temp = str1.charAt(i) - '0'; result += temp * Math.pow(2, j); j++; // 超過規定值就取餘 if (result >= Math.pow(10, 9) + 7) { result = result % (Math.pow(10, 9) + 7); } } return (int) result; }

3. 失敗反思

  • 如果n比較大,那麼拼接得到的str1會非常長,用int型別的變數i來遍歷可能不夠用。
  • 遍歷拼接,再遍歷求值,需要進行兩次遍歷操作,浪費時間。

4. 改進

(1)改進點

a.從後往前遍歷n~1,每遍歷到一個數就先轉二進位制,緊接著直接轉10進位制進行累加。
b.用long型別的變數j來記錄二進位制的位數。

(2)程式碼

 /**
     * 第二次逐個數變二進位制再逐位十進位制求和,結果也超過時間限制。
     *
     * @param n
     * @return
     */
    public int concatenatedBinary2(int n) {
        long j = 0;
        long result = 0;
        while (n > 0) {
            String str = Integer.toBinaryString(n);
            for (int i = str.length() - 1; i >= 0; i--) {
                long temp = str.charAt(i) - '0';
                result += pow(temp, j);
                j++;
                if (result >= Math.pow(10, 9) + 7) {
                    result = result % ((long) Math.pow(10, 9) + 7);
                }
            }
            n--;
        }
        return (int) result;
    }

5. 再次失敗反思

雖然將兩次遍歷合一,但是仍然需要先轉二進位制,再逐位轉十進位制,導致超時。因此思路需要轉變。

6. 演算法分析

雖然空間複雜度不高,但是佔用的記憶體很大。
時間複雜度: O ( n ) O(n) O(n)
空間複雜度: O ( 1 ) O(1) O(1)

7. 提交截圖

(1)第一次失敗截圖

在這裡插入圖片描述

(2)第二次失敗截圖

在這裡插入圖片描述

三、官網高星解法

1.位運演算法

(1)解法分析

分析示例:
n=1:result=1
n=2:result=101=100+1
n=3:result=10111=10100+11
n=4:result=10111100=10111000+100
可知,n每加1,結果相當於n-1的二進位制表示左移k位後再加n,而k就是n的二進位制表示所佔位數。
在Java中,‘<<’操作符表示左移,詳細介紹可參考:
Java基礎語法學習(二、註釋、識別符號和運算子)
也可以直接使用result*math.pow(2,左移位數)來進行左移操作。

(2)程式碼

public int concatenatedBinary(int n) {
        long result = 0;
        int i = 1;
        while (i <= n) {
            String str = Integer.toBinaryString(i);
            // sum = (sum * (long)Math.pow(2, temp.length()) + i) % mod;
            result = (result << str.length()) + i;
            if (result >= Math.pow(10, 9) + 7) {
                result = result % (long) (Math.pow(10, 9) + 7);
            }
            i++;
        }

        return (int) result;
    }

(3)演算法分析

時間複雜度: O ( n ) O(n) O(n)
空間複雜度: O ( 1 ) O(1) O(1)

(4)提交截圖

在這裡插入圖片描述