0030題 與所有單詞相關聯的字串【Substring with Concatenation of All Words】
題目:
給定一個字符串 s 和一些長度相同的單詞 words。在 s 中找出可以恰好串聯 words 中所有單詞的子串的起始位置。
注意子串要與 words 中的單詞完全匹配,中間不能有其他字符,但不需要考慮 words 中單詞串聯的順序。
示例:
輸入:
s = "barfoothefoobarman",
words = ["foo","bar"]
輸出: [0,9]
解釋: 從索引 0 和 9 開始的子串分別是 "barfoo" 和 "foobar" 。
輸出的順序不重要, [9,0] 也是有效答案。
題目不嚴謹之處:
1. words應該是不會有空字符串出現的,結果輸入數據仍然有
2. 題目的解釋中多了一個‘r’,在本博客中已經修改並刪掉
3. 題目中說到words中的單詞長度應該是統一的,示例2的words無法滿足題目條件,在本博客中已經修改並刪掉。
需要注意:
1. 不知道示例2是怎麼回事,如果出現不統一長的wordsList,那麼應該直接反饋空List
2. 沒有說明words中不允許出現相同的單詞,所以仍然需要注意
3. Robust
解題思路:
一開始沒有想到特別好的思路,嘗試暴力搜索,代碼如下:
class Solution:
def __init__(self):
self.wordsList = {}
def search(self, s, start, end, l):
tmp = self.wordsList.copy()
for i in range(start, end, l):
local = s[i:i+l]
if tmp.get(local):
if tmp[local] > 1:
tmp[local] -= 1
else:
del(tmp[local])
if len(tmp) == 0:
return True
else:
return False
def findSubstring(self, s, words):
if len(s) == 0 or len(words) == 0: return []
l = len(words[0])
cnt = len(words)
res = []
for word in words:
if self.wordsList.get(word):
self.wordsList[word] += 1
else:
self.wordsList[word] = 1
for i in range(0, len(s)):
if self.search(s, i, i+cnt*l, l):
res.append(i)
return res
emm,然後這段代碼打進去之後,竟然才爆了兩個點,點進去一看那個數據……立即加一下針對樣例的“優化”
if len(self.wordsList) == 1 and self.wordsList.get('a'):
for i in range(0, len(s)-cnt+1):
res.append(i)
return res
其實看了一波提交的答案,發現也都大同小異……之前也說過追求絕對速度是不可取的,所以這裏也直接不管了,理論上來講這道題一定有一些比較好的數據結構可以處理,但是沒有編,然後看了一下解答也並沒有,所以如果有那位大佬哪天突然有興致想編的話,可以在下面評論。
0032題 最長有效括號【Longest Valid Parentheses】
題目:
給定一個只包含 ‘(’ 和 ‘)’ 的字符串,找出最長的包含有效括號的子串的長度。
示例:
輸入: "(()"
輸出: 2
解釋: 最長有效括號子串爲 "()"
輸入: ")()())"
輸出: 4
解釋: 最長有效括號子串爲 "()()"
題目相對嚴謹
除了Robust以外,無需注意太多
解題思路:
1.題目越短的題目,難度往往都略高一些,因爲沒有辦法從題目中獲取更多的信息,自初中正式面對考試時,這種規律就沒有變過。這道題也是,看似非常容易理解的題目,但是想起來確實費一番功夫。
這題暴力搜索複雜度應該是 ,粗略估計了一下,不過肯定不能使用了,然後覺得括號匹配的題還是用棧來實現,就簡單編了一個短代碼,如下:
class Solution:
def longestValidParentheses(self, s):
res = 0
tmp_valid = 0
p = list()
for i in range(len(s)):
if s[i] == '(':
p.append(s[i])
else:
if len(p) == 0:
res = max(res, tmp_valid)
tmp_valid = 0
elif p[-1] == '(':
tmp_valid += 2
p.pop()
res = max(res, tmp_valid)
return res
不過很明顯這個是錯誤的代碼,錯誤樣例如“()(()”
,想到這種錯誤樣例,立馬意識到是因爲這段代碼過於早的pop並計算了當下可能最長長度,所以應該在既保留當下可能最長長度,又應該一直維持並沒有匹配的左括號,這裏就要注意新的兩個樣例:“()((()”,“()((())”
class Solution:
def longestValidParentheses(self, s):
res = 0
p = list()
for i in range(len(s)):
if s[i] == '(':
p.append(s[i])
else:
if len(p) == 0: continue
if p[-1] == '(':
if len(p) == 1:
p.pop()
p.append(str(2))
else:
tmp = 2
p.pop()
while len(p) > 0 and p[-1].isdigit(): tmp += int(p.pop())
p.append(str(tmp))
elif p[-1].isdigit():
if len(p) == 1:
res = max(res, int(p[-1]))
p = list()
else:
tmp = int(p.pop()) + 2
p.pop()
while len(p) > 0 and p[-1].isdigit(): tmp += int(p.pop())
p.append(str(tmp))
for c in p:
if c.isdigit():
res = max(res, int(c))
return res
2.這樣做無非是在不動腦子的模擬操作,這道題的提示中有着動態規劃四個字,思來想去,覺得如果是DP的話,更新點肯定是在右括號,那就是字符串中有什麼規律可循,參考網上的解答貼:https://blog.csdn.net/accepthjp/article/details/52439449,才發現如下規律:
dp[i]表示以當前位置爲終點的最長長度,則只能在)處更新,
如果s[i-1-dp[i-1]]==’(‘,則說明當前位置可以和i-1-dp[i-1]位置匹配,dp[i]=dp[i-1]+2
然後還要加上匹配位置之前的最長長度dp[i]+=dp[i-dp[i]]
自己在草稿紙上演算了一下,還真是這個道理,有點自嘆不如……附上最後的代碼:
class Solution:
def longestValidParentheses(self, s):
max_len = 0
dp = [-1]
for i in range(len(s)):
if s[i] == '(':
dp.append(i)
else:
dp.pop()
if(len(dp) == 0):
dp.append(i)
else:
max_len = max(max_len, i - dp[-1])
return max_len
0036題 有效的數獨【Valid Sudoku】
題目:
判斷一個 9x9 的數獨是否有效。只需要根據以下規則,驗證已經填入的數字是否有效即可。
- 數字 1-9 在每一行只能出現一次。
- 數字 1-9 在每一列只能出現一次。
- 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。
數獨部分空格內已填入了數字,空白格用 ‘.’ 表示。
說明:
- 一個有效的數獨(部分已被填充)不一定是可解的。
- 只需要根據以上規則,驗證已經填入的數字是否有效即可。
- 給定數獨序列只包含數字 1-9 和字符 ‘.’ 。
- 給定數獨永遠是 9x9 形式的。
示例:
輸入:
[
["5","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
輸出: true
輸入:
[
["8","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
輸出: false
解釋: 除了第一行的第一個數字從 5 改爲 8 以外,空格內其他數字均與 示例1 相同。
但由於位於左上角的 3x3 宮內有兩個 8 存在, 因此這個數獨是無效的。
題目相對嚴謹
無需注意太多
解題思路:
【密恐症人慎入的幾道題(棒讀)】
這題僅僅是判斷數獨是否有效,而並不是判斷數獨可否有解,所以工作量頓時降低。
簡單模擬題目就好,這裏不放上那麼冗餘的代碼了。
0037題 解數獨【Sudoku Solver】
題目:
編寫一個程序,通過已填充的空格來解決數獨問題。
一個數獨的解法需遵循如下規則:
- 數字 1-9 在每一行只能出現一次。
- 數字 1-9 在每一列只能出現一次。
- 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。
說明:
- 一個有效的數獨(部分已被填充)不一定是可解的。
- 只需要根據以上規則,驗證已經填入的數字是否有效即可。
- 給定數獨序列只包含數字 1-9 和字符 ‘.’ 。
- 給定數獨永遠是 9x9 形式的。
空白格用 ‘.’ 表示。
題目相對嚴謹
經典題目無需注意太多
解題思路:
這是所有搜索題目的經典題,DFS或者BFS都可以解,然後就想到當年看到解數獨時候的Dancing Links……舞蹈鏈算法並不是在這裏用的,會爆炸。
因爲是經典回溯搜索題目,所以就不post代碼了。
0038題 報數【Count and Say】
題目:
報數序列是指一個整數序列,按照其中的整數的順序進行報數,得到下一個數。其前五項如下:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 被讀作 “one 1” (“一個一”) , 即 11。
11 被讀作 “two 1s” (“兩個一”), 即 21。
21 被讀作 “one 2”, “one 1” (”一個二” , “一個一”) , 即 1211。
給定一個正整數 n ,輸出報數序列的第 n 項。
注意:整數順序將表示爲一個字符串。
示例:
輸入: 1
輸出: "1"
輸入: 4
輸出: "1211"
題目相對嚴謹
除Robust以外,無需注意太多。
解題思路:
emmm,一開始看題感覺有點懵,不知道在說什麼,後來想想無非還是模擬題。
post代碼:
class Solution:
def nxt(self, s):
ss = ""
n = len(s)
i = 0
while i < n:
tmp = i + 1
while tmp < n and s[tmp] == s[i]: tmp += 1
ss += str(tmp - i) + s[i]
i = tmp
return ss
def countAndSay(self, n):
res = ['1']
for i in range(1, n):
res.append(self.nxt(res[-1]))
return res[-1]
如果有數學解法的話,歡迎評論……
0039題 組合總和【Combination Sum】
題目:
給定一個無重複元素的數組 candidates 和一個目標數 target ,找出 candidates 中所有可以使數字和爲 target 的組合。
candidates 中的數字可以無限制重複被選取。
說明:
- 所有數字(包括 target)都是正整數。
- 解集不能包含重複的組合。
示例:
輸入: candidates = [2,3,6,7], target = 7,
所求解集爲:
[
[7],
[2,2,3]
]
輸入: candidates = [2,3,5], target = 8,
所求解集爲:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
題目相對嚴謹
除Robust以外無需注意太多
解題思路:
好吧,這是一道再經典不過的回溯題目了,直接AC掉,無需post代碼