第7周Leetcode記錄
10.30 32.移動石子
三枚石子放置在數軸上,位置分別為 a,b,c。
每一回合,我們假設這三枚石子當前分別位於位置 x, y, z 且 x < y < z。從位置 x 或者是位置 z 拿起一枚石子,並將該石子移動到某一整數位置 k 處,其中 x < k < z 且 k != y。
當你無法進行任何移動時,即,這些石子的位置連續時,遊戲結束。
要使遊戲結束,你可以執行的最小和最大移動次數分別是多少? 以長度為 2 的陣列形式返回答案:answer = [minimum_moves, maximum_moves]
思路
最少0或1或2,分情況。
我的解
class Solution: def numMovesStones(self, a: int, b: int, c: int) -> List[int]: tmp = [a,b,c] # 先對xyz賦值 tmp.sort() x,y,z = tmp[0],tmp[1],tmp[2] if x + 1 == y and y + 1 == z: # a,b,c連續 return [0,0] else: if y-x == 2 or z-y == 2 or (x+1 == y or y + 1 == z): # 中間隔一個或者有兩個挨著 minimum_moves = 1 else: minimum_moves = 2 maximum_moves = (y-x)+(z-y)-2 return [minimum_moves,maximum_moves]
11.1 33. 拼寫單詞
給你一份『詞彙表』(字串陣列) words 和一張『字母表』(字串) chars。
假如你可以用 chars 中的『字母』(字元)拼寫出 words 中的某個『單詞』(字串),那麼我們就認為你掌握了這個單詞。
注意:每次拼寫(指拼寫詞彙表中的一個單詞)時,chars 中的每個字母都只能用一次。
返回詞彙表 words 中你掌握的所有單詞的 長度之和。
輸入:words = ["cat","bt","hat","tree"], chars = "atach"
輸出:6
解釋:
可以形成字串 "cat" 和 "hat",所以答案是 3 + 3 = 6。
思路
用counter將chars每個字母出現的次數提取出來,分別遍歷數組裡每一個單詞的counter,符合條件的即是。
我的解
class Solution: def countCharacters(self, words: List[str], chars: str) -> int: from collections import Counter from copy import deepcopy chars_dic = Counter(chars) res_list = [] for word in words: fit = 1 dic_copy = deepcopy(chars_dic) per_dic = Counter(word) dic_copy.subtract(per_dic) for i in dic_copy.values(): if i < 0: fit = 0 break if fit: res_list.append(word) return len(''.join(res_list))
11.2 34. 搜尋旋轉排序陣列
給你一個升序排列的整數陣列 nums ,和一個整數 target 。
假設按照升序排序的陣列在預先未知的某個點上進行了旋轉。(例如,陣列 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。
請你在陣列中搜索 target ,如果陣列中存在這個目標值,則返回它的索引,否則返回 -1 。
輸入:nums = [4,5,6,7,0,1,2], target = 0
輸出:4
輸入:nums = [4,5,6,7,0,1,2], target = 3
輸出:-1
思路
可以遍歷,時間複雜度高。
利用二分法,分為L,R兩個陣列,因為是有序陣列分的。如果L和R都是有序,判斷target在哪個區間。繼續二分。如果L[0] > L[-1] 說明L無序,如果target在R裡,可以丟棄L,如果target不在,繼續二分。判斷並丟棄。
最優解
class Solution:
@classmethod
def search(self, nums: list, target: int) -> int:
if not nums:
return -1
l, r = 0, len(nums) - 1
while l <= r:
mid = (l + r) // 2
if nums[mid] == target:
return mid
if nums[0] <= nums[mid]:
if nums[0] <= target < nums[mid]:
r = mid - 1
else:
l = mid + 1
else:
if nums[mid] < target <= nums[len(nums) - 1]:
l = mid + 1
else:
r = mid - 1
return -1
總結
每次可以至少得到一個有序區間,如果target在此區間丟棄另一個,如果不在丟棄自身。
11.3 35. 恢復二叉搜尋樹
給你二叉搜尋樹的根節點 root
,該樹中的兩個節點被錯誤地交換。請在不改變其結構的情況下,恢復這棵樹。
輸入:root = [1,3,null,null,2]
輸出:[3,1,null,null,2]
解釋:3 不能是 1 左孩子,因為 3 > 1 。交換 1 和 3 使二叉搜尋樹有效。
輸入:root = [3,1,4,null,null,2]
輸出:[2,1,4,null,null,3]
解釋:2 不能在 3 的右子樹中,因為 2 < 3 。交換 2 和 3 使二叉搜尋樹有效。
最優解一:顯示中序遍歷
-
為什麼用中序
根據題意,任意根節點,左邊比根節點小,右邊比根節點大。有序的搜素樹中序遍歷一定有序
class Solution(object): def recoverTree(self, root): nodes = [] # 中序遍歷二叉樹,並將遍歷的結果儲存到list中 def dfs(root): if not root: return dfs(root.left) nodes.append(root) dfs(root.right) dfs(root) x = None y = None pre = nodes[0] # 掃面遍歷的結果,找出可能存在錯誤交換的節點x和y for i in xrange(1,len(nodes)): if pre.val>nodes[i].val: y=nodes[i] if not x: x = pre pre = nodes[i] # 如果x和y不為空,則交換這兩個節點值,恢復二叉搜尋樹 if x and y: x.val,y.val = y.val,x.val