目錄
注意:
主要和b站大雪菜一起刷題,寶藏up主(https://www.bilibili.com/video/BV1Vt411M741)
38. 外觀數列
思路:
- 這道題是個模擬題
- 每一輪循環尋找連續字符
- 注意循環是n-1
class Solution:
def countAndSay(self, n: int) -> str:
res = "1"
for i in range(n-1):
tmp = ""
j = 0
while j<len(res):
k = j
while (k<len(res)) and (res[k]==res[j]):
k += 1
tmp += str(k-j)+res[j]
j = k
res = tmp
return res
49. 字母異位詞分組
思路:
- 字母的異位詞,我們要找到它們的共同點
- 可以對每個詞進行排序,字母相同的詞排序結果是一樣的,就可以進行分組
- python對字符串進行sorted之後是個list,不是str類型,需要處理
- 排序的總時間O(nmlogm+n)n個詞,m爲長度
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
dic = {}
for s in strs:
tmp = s
tmp = ''.join(sorted(tmp))
# print(tmp)
dic[tmp] = dic.get(tmp, []) + [s]
res = []
for v in dic.values():
res.append(v)
return res
151. 翻轉字符串裏的單詞
思路:
- 可以每個單詞進行翻轉,再對整個字符串翻轉
- 這裏用python的strip、split,會更方便一點
class Solution:
def reverseWords(self, s: str) -> str:
s = s.strip()
s = s.split(' ')
i = 0
while i<len(s):
if s[i] == '':
s.pop(i)
continue
i += 1
return ' '.join(s[::-1])
165. 比較版本號
思路:
- 將版本號根據'.'分隔開,依次比較,若相等則繼續比較下一段
- 若不相等直接比較大小返回1或-1
class Solution:
def compareVersion(self, version1: str, version2: str) -> int:
i,j=0,0
while i<len(version1) or j<len(version2):
x,y = i, j
while x<len(version1) and version1[x] != '.':
x += 1
while y<len(version2) and version2[y] != '.':
y += 1
a = 0 if x==i else int(version1[i:x])
b = 0 if y==j else int(version2[j:y])
if a<b:
return -1
if a>b:
return 1
i = x+1
j = y+1
return 0
929. 獨特的電子郵件地址
思路:
- 用find函數,find(str,begin,end)找到‘@’的下標
- 將email地址分割成name+domain,然後對name進行單獨的處理,再與‘@’和domain組合獲得新的郵件地址,得到最後的答案
- 用set去重存儲所有的答案,返回set的長度即可
class Solution:
def numUniqueEmails(self, emails: List[str]) -> int:
res = set()
for email in emails:
at = email.find('@')
name = ""
for c in email[:at]:
if c == '+':
break
elif c != '.':
name += c
domain = email[at+1:]
s = name+"@"+domain
res.add(s)
return len(res)
5. 最長迴文子串
思路:
- 枚舉每一個可能的中心點,分別用j,k兩個指針向兩邊擴展,所指指針相等則繼續移動,不相等則跳出判斷是不是最長的
- 中心點可能是兩個(迴文子串長度爲偶數),也可能是一個(迴文子串長度爲奇數)
- 時間複雜度爲O(n^2),n爲s的長度
class Solution:
def longestPalindrome(self, s: str) -> str:
max_res = ""
for i in range(len(s)):
j,k=i,i
# 迴文串長度爲奇數
while j>=0 and k<len(s) and s[j] == s[k]:
j -= 1
k += 1
tmp = s[j+1:k]
if len(tmp) > len(max_res):
max_res = tmp
j,k=i,i+1
# 迴文串長度爲偶數
while j>=0 and k<len(s) and s[j] == s[k]:
j -= 1
k += 1
tmp = s[j+1:k]
if len(tmp) > len(max_res):
max_res = tmp
return max_res
6. Z 字形變換
思路:
- 這題主要是找規律,第一排和最後一排都是首項爲i,公差爲2*(numrows-1)
- 中間的部分是兩個等差數列交叉出現
class Solution:
def convert(self, s: str, numRows: int) -> str:
if numRows==1:
return s
res = ""
for i in range(numRows):
# 第一行或者最後一行
if i==0 or i==numRows-1:
j = i
while j<len(s):
res += s[j]
j += 2*(numRows-1)
else:# 其餘行
j,k=i,2*(numRows-1)-i
while j<len(s) or k<len(s):
res += s[j] if j<len(s) else ""
res += s[k] if k<len(s) else ""
j += 2*(numRows-1)
k += 2*(numRows-1)
return res
3. 無重複字符的最長子串
思路:
- 利用雙指針,i代表當前無重複字符子串的頭,j代表當前無重複字符子串的尾
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if not s:
return 0
i = 0
max_len = 1
for j in range(1,len(s)):
while s[j] in s[i:j]:
i += 1
if j-i+1>max_len:
max_len = j-i+1
return max_len
208. 實現 Trie (前綴樹)
思路:
- 前綴樹的結構就是,根節點爲空,每一個節點有26個子節點,出現那個字符就將對應位置的指針賦予它
- 每一個節點還要標記下當前節點是不是某個單詞的結尾
class Node:
def __init__(self):
self.is_end = False
self.son = [None]*26
class Trie:
def __init__(self):
"""
Initialize your data structure here.
"""
self.root = Node()
def insert(self, word: str) -> None:
"""
Inserts a word into the trie.
"""
p = self.root
for ch in word:
index = ord(ch) - ord('a')
if not p.son[index]:
p.son[index] = Node()
p = p.son[index]
p.is_end = True
def search(self, word: str) -> bool:
"""
Returns if the word is in the trie.
"""
p = self.root
for ch in word:
index = ord(ch) - ord('a')
if not p.son[index]:
return False
p = p.son[index]
return p.is_end
def startsWith(self, prefix: str) -> bool:
"""
Returns if there is any word in the trie that starts with the given prefix.
"""
p = self.root
for ch in prefix:
index = ord(ch) - ord('a')
if not p.son[index]:
return False
p = p.son[index]
return True
# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)
273. 整數轉換英文表示
思路:
- 這題主要是比較麻煩,但是想清楚就會好一點。
- 英文中是三個數字三個數字爲一部分,__billion__million__thousand__,其中__爲1~999,最後一個爲0~999
- 對於1000以內的數寫一個表達函數,然後套入上面這個形式就可以
class Solution:
def __init__(self):
self.small = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven"
"Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen",
"Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"]
self.decade = ["", "", "Twenty", "Thirty", "Fourty", "Fifty", "Sixty", "Seventy",
"Eighty", "Ninety"]
self.big = ["", "Thousand", "Million", "Billion"]
def numberToWords(self, num: int) -> str:
if num == 0:
return self.small[0]
i,j = 1000000000, 3
res = ""
while i and j>=0:
if num>i:
res += self.get_part(num//i) + self.big[j]
i //= 1000
j -= 1
res = res.strip()
return res
# 1000以內表達形式
def get_part(self, num):
res = ""
if num > 100:
res += self.small[num//100] + " Hundred "
num %= 100
if not num:
return res
if num > 20:
res += self.decade[num//10] + ' '
num %= 10
if not num:
return res
else:
res += self.small[num] + ' '
return res
166. 分數到小數
思路:
- 又是一道模擬題,要把步驟捋清楚
- 首先判斷分子分母是不是負數,是的話需要進行處理成正數,同時記錄下結果是否要添加負號
- 然後來計算,首先整除了沒有餘數了就可以直接輸出答案
- 若是餘數不爲0說明還有小數部分,小數部分的計算就和手算步驟一樣,關鍵是如何判斷是循環節
- 用一個dic哈希表儲存當前數字的位置,若有一個數字之前存在過,則後面的餘數會是一樣的,就可以得出循環節
class Solution:
def fractionToDecimal(self, numerator: int, denominator: int) -> str:
minus = False
if numerator<0:
minus = not minus
numerator = -numerator
if denominator<0:
minus = not minus
denominator = -denominator
res = str(numerator//denominator)
numerator = numerator%denominator
# 整除
if not numerator:
if minus and res!="0":
res = "-"+res
return res
# 計算小數部分
res += "."
dic = {}
while numerator:
if dic.get(numerator,0):
res = res[:dic[numerator]] + "(" +res[dic[numerator]:] + ")"
break
else:
dic[numerator] = len(res)
numerator *= 10
res += str(numerator//denominator)
numerator %= denominator
if minus:
res = "-"+res
return res
131. 分割回文串
思路:
- l這道題利用dfs+回溯遍歷所有方案即可
- 寫個判斷迴文串的函數
class Solution:
def partition(self, s: str) -> List[List[str]]:
res = []
self.dfs("", 0, s, res, [])
return res
def dfs(self, now, cur, s, ans, path):
if cur == len(s):
if self.check(now):
path.append(now)
ans.append(path[:])
path.pop()
return
if self.check(now):
path.append(now)
self.dfs("", cur, s, ans, path)
path.pop()
self.dfs(now+s[cur], cur+1, s, ans, path)
def check(self, s):
if not s:
return False
i,j=0, len(s)-1
while i<j:
if s[i]!=s[j]:
return False
i += 1
j -= 1
return True
227. 基本計算器 II
思路:
- 又是一道想起來比較複雜的題,由於有加減乘除的符號,考慮符號的優先級,可以用兩個棧,一個存儲符號,一個存儲數字
- 若是數字就要進行計算,查看棧頂,是乘除符號則直接計算,若是加減符號則判斷下棧裏的加減符號有沒有超過兩個,(a+b+c*d)這裏可以發現a+b可以先計算的。
- 在原本數字的末尾添加+0方便棧最後進行計算
class Solution:
def calculate(self, s: str) -> int:
op, num = [], []
s += "+0"
i = 0
while i<len(s):
# 空格跳過
if s[i] == ' ':
i += 1
continue
# 符號
if s[i] == '+' or s[i] == '-' or s[i] == '*' or s[i] == '/':
op.append(s[i])
else:
# 獲取數字
j = i
while j<len(s) and ('0'<=s[j]<='9'):j+=1
num.append(int(s[i:j]))
i = j-1
# 操作符棧非空
if op:
if op[-1]=='*' or op[-1]=='/':
x = num.pop()
y = num.pop()
if op[-1]=='*':
num.append(x*y)
else:
num.append(y//x)
op.pop()
elif len(op)>=2:
c = num.pop()
b = num.pop()
a = num.pop()
op2 = op.pop()
op1 = op.pop()
if op1 == '+':
num.append(a+b)
else:
num.append(a-b)
num.append(c)
op.append(op2)
i += 1
num.pop()
# print(num)
return num[-1]