問題
思路及解答
Leetcode 上面的變形題目,詳見下面三道翻轉字符串題目。
# 方法:先把不是空格的元素存在一個列表中,進行翻轉之後再將其由空格分隔。
s = " the sky is blue! "
s = s.split()
l = len(s)
strList = []
for i in range(l):
if s[i] != " ":
strList.append(s[i])
def reverse_s(s):
left, right = 0, len(s) - 1
while left < right:
s[left], s[right] = s[right], s[left]
left, right = left + 1, right - 1
return s
print(" ".join(reverse_s(strList)))
問題1
編寫一個函數,其作用是將輸入的字符串反轉過來。輸入字符串以字符數組 char[] 的形式給出。
不要給另外的數組分配額外的空間,你必須原地修改輸入數組、使用 O(1) 的額外空間解決這一問題。
你可以假設數組中的所有字符都是 ASCII 碼錶中的可打印字符。
示例 1:
輸入:["h","e","l","l","o"]
輸出:["o","l","l","e","h"]
示例 2:
輸入:["H","a","n","n","a","h"]
輸出:["h","a","n","n","a","H"]
思路及解答
# 方法一:直接翻轉
# 注意:s[::-1] 沒有修改 s 內部,只是做了翻轉輸出
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
s[:] = s[::-1]
# 方法二:.reverse() 函數
# 注意:.reverse() 從數組內部修改了元素
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
s.reverse()
# 方法三:雙指針(對撞指針)
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
left, right = 0, len(s)-1
while(left < right):
s[left], s[right] = s[right], s[left]
left, right = left + 1, right - 1
# 方法四:異或操作(三次異或可以實現字符的交換),異或操作不需要額外地開闢空間
# 注意:對於數字可以直接異或,對於字符需要用 ord(ch) 將 ch 轉換 ASCII 碼再進行異或操作,字符異或之後用 chr() 函數再將 ASCII 碼轉化爲字符
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
left, right = 0, len(s)-1
while left < right:
s[left] = chr(ord(s[left]) ^ ord(s[right]))
s[right] = chr(ord(s[right]) ^ ord(s[left]))
s[left] = chr(ord(s[left]) ^ ord(s[right]))
left, right = left + 1, right - 1
# 遞歸調用
# 待續
問題2
給定一個字符串和一個整數 k,你需要對從字符串開頭算起的每個 2k 個字符的前k個字符進行反轉。如果剩餘少於 k 個字符,則將剩餘的所有全部反轉。如果有小於 2k 但大於或等於 k 個字符,則反轉前 k 個字符,並將剩餘的字符保持原樣。
示例:
輸入: s = "abcdefg", k = 2
輸出: "bacdfeg"
要求:該字符串只包含小寫的英文字母。給定字符串的長度和 k 在[1, 10000]範圍內。
思路及解答
# 方法:遞歸
# 重點在於反轉區間的判斷,方法如下:
1. 若長度小於 k,則翻轉所有;
2. 若長度大於等於 k,小於 2k,則翻轉前 k 個;
3. 若長度大於 2k,則翻轉這 2k 箇中的前 k 個,再遞歸檢查除去這 2k 個元素剩下的字符串長度,由此作 1/2/3 的操作。
# 翻轉函數,start 和 end 是翻轉區間的索引起始(包含 start 和 end)
def reverse_Str(s, start, end):
left, right = start, end
while left < right:
s[left], s[right] = s[right], s[left]
left, right = left + 1, right - 1
return s
class Solution:
def reverseStr(self, s: str, k: int) -> str:
l = len(s)
s = list(s)
if k <= l < 2 * k:
return "".join(reverse_Str(s, 0, k - 1))
elif l < k:
return "".join(reverse_Str(s, 0, l - 1))
else:
start, end = 0, l - 1
while end - start + 1 >= 2 * k:
reverse_Str(s, start, start + k - 1)
start = start + 2 * k
if end - start >= k:
return "".join(reverse_Str(s, start, start + k - 1))
else:
return "".join(reverse_Str(s, start, end))
問題3
給定一個字符串,你需要反轉字符串中每個單詞的字符順序,同時仍保留空格和單詞的初始順序。
示例 1:
輸入: "Let's take LeetCode contest"
輸出: "s'teL ekat edoCteeL tsetnoc"
注意:在字符串中,每個單詞由單個空格分隔,並且字符串中不會有任何額外的空格。
思路及解答
# 方法:把字符串存在列表中,對於每個列表元素(可能是多個字符)分別進行翻轉,最後再組合輸出(由空格分隔)
def reverse_s(strs):
strs = list(strs) # 長度爲 5
left, right = 0, len(strs) - 1
while left < right:
strs[left], strs[right] = strs[right], strs[left]
left, right = left + 1, right - 1
return "".join(strs)
class Solution:
def reverseWords(self, s: str) -> str:
s = s.split()
l = len(s) # 長度爲 4
result = []
for i in range(l):
result.append(reverse_s(s[i]))
return " ".join(result)
############### 可供參考的思路 ##################
遍歷字符串列表,如果爲空則跳過;不爲空則添加在輸出字符串的最前面!
知識點
1. 字符串長度的操作(兩種)
例如:s = "let's play together"
(1) len(s.split()) = 3,有 .split() 是將字符串由默認字符分隔之後,存成列表;
(2) len(s) = 19,沒有 .split() 是輸出原字符串的長度(包含兩個空格長度和一個 \' 的長度)。
2. 字符串和列表的相互轉換
(1) 字符串轉換爲列表: s.split()
(2) 列表轉換爲字符串:"sep".join(s)
注意:eval() 會執行括號裏面的!
(參考:python字符串與列表的相互轉換)
3. 三次異或交操作換兩個元素
簡單來理解就是:對於 a ^ b ^ b,因爲 b ^ b 兩個完全相同,那麼異或結果爲 0 ,a ^ 0 結果爲 a,因此同理:a = a ^ b ^ a; b = a ^ b ^ b,這樣就實現了 a 和 b 的交換。即:
a = a ^ b
b = a ^ b (這裏執行完 b 已經成了 a)
a = a ^ b (這裏 a 是 a ^ b,b 是 a)
需要注意的是:進行異或時,必須是數值異或,如果是字符進行異或,首先要用 ord(ch) 轉換成其對應的 ASCII 碼值,異或完再用 chr(num) 轉換爲結果字符。(兩函數見下面講解)
(參考:C語言爲什麼能夠通過異或交換兩值)
(參考:爲什麼三次異或操作可以交換兩個數)
4. .join() 的使用:可以將列表輸出爲字符串!!!
5. .reverse() 和 s[::-1] 是否從內部修改數組?
(1) s.reverse() 實現了內部修改,但要注意的是 .reverse() 函數沒有返回值,因此如果把它寫在函數裏面的話,若函數需要有返回值,那麼它實現不了功能。
(2) s[::-1] 沒有從內部修改,它只是做了翻轉輸出,但沒有修改數組元素。
6. s[:] 是指 輸出 s 整個數組!!!
7. ord(ch) 和 chr(num) 的使用
(1) ord(c),c 是字符。其返回值是對應的十進制整數。(ASCII 碼)
(2) chr(num),num 是 ASCII 碼。其返回值是字符。
兩個函數互逆。
(參考:Python ord() 函數)