將一個給定字串根據給定的行數,以從上往下、從左到右進行 Z 字形排列。
比如輸入字串為 "LEETCODEISHIRING"
行數為 3 時,排列如下:
L C I R
E T O E S I I G
E D H N
之後,你的輸出需要從左往右逐行讀取,產生出一個新的字串,比如:"LCIRETOESIIGEDHN"
。
請你實現這個將字串進行指定行數變換的函式:
string convert(string s, int numRows);
示例 1:
輸入: s = “LEETCODEISHIRING”, numRows = 3
輸出: “LCIRETOESIIGEDHN”
示例 2:
輸入: s = “LEETCODEISHIRING”, numRows = 4
輸出: “LDREOEIIECIHNTSG”
解釋:L D R
E O E I I
E C I H N
T S G
解題思路:
- 題目理解:
字串 s
是以 Z 字形為順序儲存的字串,目標是按行列印。
設 numRows
行字串分別為 s_1, s_2,…, s_n,則容易發現:按順序遍歷字串 s
時,每個字元 c
在 Z 字形中對應的 行索引 先從 s_1增大至 s_n,再從 s_n減小至 s_1 …… 如此反覆。
因此,解決方案為:模擬這個行索引的變化,在遍歷 s
中把每個字元填到正確的行 zWord[row]
。
- 演算法流程: 按順序遍歷字串
s
;
zWord[row] += c
: 把每個字元 c
填入對應行 s_{row};
row += goingDown
: 更新當前字元 c
對應的行索引;
goingDown = - goingDown
: 在達到 Z 字形轉折點時,執行反向。
- 複雜度分析:
時間複雜度 O(N) :遍歷一遍字串 s;
空間複雜度 O(N) :各行字串共佔用 O(N) 額外空間。
class Solution {
public:
string convert(string s, int numRows) {
if (numRows == 1) return s;//注意特判,numRows為1時,不會向下或向上拼接,只輸出一行也就是原字串,後面的程式會失效越界。
vector<string> zWord(min((int) s.length(), numRows));//防止出現字串長度小於行數的情況,s.length()返回型別是size_t,所以要強制型別轉換一下才能用min
int goingDown = -1;//行數加一或減一,初始值應為-1,因為第一次迴圈進判斷會取反,這是第一行。
int row = 0;//從第一行開始
for (auto &c:s) {//遍歷字串
zWord[row] += c;//把字元拼接在應該在的那一行的字串上
if (row == 0 || row == numRows - 1) {//第一行或最後一行就方向調轉,注意是0和numRows-1
goingDown = -goingDown;//遇到第一行應該為1,最後一行應該為-1
}
row += goingDown;//行數逐漸增加或減小,來回振盪
}
string ans;
for (auto &s:zWord) {//從上到下遍歷行
ans += s;//把z變換後的每一行拼接起來
}
return ans;
}
};
給出一個 32 位的有符號整數,你需要將這個整數中每位上的數字進行反轉。
示例 1:
輸入: 123
輸出: 321
示例 2:
輸入: -123
輸出: -321
示例 3:
輸入: 120
輸出: 21
注意:
假設我們的環境只能儲存得下 32 位的有符號整數,則其數值範圍為 [−231, 231 − 1]。請根據這個假設,如果反轉後整數溢位那麼就返回 0。
解題思路:
作者:wang_ni_ma
連結:leetcode-cn.com/problems/reverse-i...
來源:力扣(LeetCode)
首先我們想一下,怎麼去反轉一個整數?
用棧?
或者把整數變成字串,再去反轉這個字串?
這兩種方式是可以,但並不好。實際上我們只要能拿到這個整數的 末尾數字 就可以了。
以12345
為例,先拿到5
,再拿到4
,之後是3
,2
,1
,我們按這樣的順序就可以反向拼接處一個數字了,也就能達到 反轉 的效果。
怎麼拿末尾數字呢?好辦,用取模運算就可以了
- 將
12345 % 10
得到5
,之後將12345 / 10
- 將
1234 % 10
得到4
,再將1234 / 10
- 將
123 % 10
得到3
,再將123 / 10
- 將
12 % 10
得到2
,再將12 / 10
- 將
1 % 10
得到1
,再將1 / 10
這麼看起來,一個迴圈就搞定了,迴圈的判斷條件是x>0
但這樣不對,因為忽略了 負數
迴圈的判斷條件應該是while(x!=0)
,無論正數還是負數,按照上面不斷的/10
這樣的操作,最後都會變成0,所以判斷終止條件就是!=0
有了取模和除法操作,對於像12300
這樣的數字,也可以完美的解決掉了。
看起來這道題就這麼解決了,但請注意,題目上還有這麼一句
- 假設我們的環境只能儲存得下
32
位的有符號整數,則其數值範圍為[−2^31, 2^31 − 1]
。
也就是說我們不能用long
儲存最終結果,而且有些數字可能是合法範圍內的數字,但是反轉過來就超過範圍了。
假設有1147483649
這個數字,它是小於最大的32
位整數2147483647
的,但是將這個數字反轉過來後就變成了9463847411
,這就比最大的32
位整數還要大了,這樣的數字是沒法存到int
裡面的,所以肯定要返回0
(溢位了)。
甚至,我們還需要提前判斷
上圖中,綠色的是最大32
位整數
第二排數字中,橘子的是5
,它是大於上面同位置的4
,這就意味著5
後跟任何數字,都會比最大32
為整數都大。
所以,我們到最大數的1/10時,就要開始判斷了
如果某個數字大於 214748364
那後面就不用再判斷了,肯定溢位了。
如果某個數字等於 214748364
呢,這對應到上圖中第三、第四、第五排的數字,需要要跟最大數的末尾數字比較,如果這個數字比7
還大,說明溢位了。
對於負數也是一樣的
上圖中綠色部分是最小的32
位整數,同樣是在最小數的 1/10時開始判斷
如果某個數字小於 -214748364
說明溢位了
如果某個數字等於 -214748364
,還需要跟最小數的末尾比較,即看它是否小於8
TIPS
通過包含標頭檔案<limits.h>
使用INT_MAX
和INT_MIN
而不用直接打數字,使程式閱讀更直觀。
class Solution {
public:
int reverse(int x) {
int ans = 0;
while (x) {//最後一位加上後x=0
int temp = x % 10;
//只需要考慮最後一次是否越界,因為後面相加如果越界了就無法判斷了,所以要在少一位時判斷前n-1位以及最後一位與INT_MAX和INT_MIN前n-1位以及最後一位比較
if (ans > INT_MAX / 10 || (ans == INT_MAX / 10 && temp > INT_MAX % 10))
return 0;//前n-1位大了,後面就不用看,如果前n-1位一樣,看最後一位是否溢位
if (ans < INT_MIN / 10 || (ans == INT_MIN / 10 && temp < INT_MIN % 10))
return 0;//前n-1位小了,後面就不用看,如果前n-1位一樣,看最後一位是否溢位
ans = ans * 10 + temp;//溢位返回0,不溢位正常運算
x /= 10;
}
return ans;
}
};
本作品採用《CC 協議》,轉載必須註明作者和本文連結