1. 程式人生 > 實用技巧 >第7周Leetcode記錄

第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