【20190829】【校招筆試題】翻轉字符串 + 翻轉字符串中的單詞(Leetcode 344,541,557) + 小紅書 2019 筆試第一題

問題


思路及解答

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() 函數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章