Leetcode小白試煉(20201207 連線連續二進位制數字)
技術標籤:演算法程式設計學習字串演算法javaleetcode
文章目錄
一、題目
1. 題目描述
給你一個整數 n ,請你將 1 到 n 的二進位制表示連線起來,並返回連線結果對應的 十進位制 數字對 109 + 7 取餘的結果。
提示:
1
≤
n
≤
1
0
5
1 \leq n \leq10^5
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)