leetcode刷題記錄431-440 python版

前言

繼續leetcode刷題生涯
這裏記錄的都是筆者覺得有點意思的做法
參考了好幾位大佬的題解,尤其是powcai大佬和labuladong大佬,感謝各位大佬

432. 全 O(1) 的數據結構

# 雙向鏈表
# 定義雙向節點
class Node:
    def __init__(self, cnt):
        self.cnt = cnt
        # 記錄該cnt(計數)下key包括哪些
        self.keySet = set()
        # 前後指針
        self.prev = None
        self.next = None
class AllOne:
    def __init__(self):
        """
        Initialize your data structure here.
        """
        # 記錄頭尾 便於求最小值最大值
        self.head = Node(float("-inf"))
        self.tail = Node(float("inf"))
        # 首尾相連
        self.head.next = self.tail
        self.tail.prev = self.head
        # 個數對應的節點
        self.cntKey = {}
        # key 對應的個數
        self.keyCnt = {}
    def inc(self, key: str) -> None:
        """
        Inserts a new key <Key> with value 1. Or increments an existing key by 1.
        """
        if key in self.keyCnt:
            self.changeKey(key, 1)
        else:
            self.keyCnt[key] = 1
            # 說明沒有計數爲1的節點,在self.head後面加入
            if self.head.next.cnt != 1:
                self.addNodeAfter(Node(1), self.head)
            self.head.next.keySet.add(key)
            self.cntKey[1] = self.head.next
    def dec(self, key: str) -> None:
        """
        Decrements an existing key by 1. If Key's value is 1, remove it from the data structure.
        """
        if key in self.keyCnt:
            cnt = self.keyCnt[key]
            if cnt == 1:
                self.keyCnt.pop(key)
                self.removeFromNode(self.cntKey[cnt], key)
            else:
                self.changeKey(key, -1)
    def getMaxKey(self) -> str:
        """
        Returns one of the keys with maximal value.
        """
        return "" if self.tail.prev == self.head else next(iter(self.tail.prev.keySet))
    def getMinKey(self) -> str:
        """
        Returns one of the keys with Minimal value.
        """
        return "" if self.head.next == self.tail else next(iter(self.head.next.keySet))
    # key加1或者減1
    def changeKey(self, key, offset):
        cnt = self.keyCnt[key]
        self.keyCnt[key] = cnt + offset
        curNode = self.cntKey[cnt]
        newNode = None
        if cnt + offset in self.cntKey:
            newNode = self.cntKey[cnt + offset]
        else:
            newNode = Node(cnt + offset)
            self.cntKey[cnt + offset] = newNode
            self.addNodeAfter(newNode, curNode if offset == 1 else curNode.prev)
        newNode.keySet.add(key)
        self.removeFromNode(curNode, key)
    # 在prevNode後面加入newNode
    def addNodeAfter(self, newNode, prevNode):
        newNode.prev = prevNode
        newNode.next = prevNode.next
        prevNode.next.prev = newNode
        prevNode.next = newNode
    # 在curNode刪除key
    def removeFromNode(self, curNode, key):
        curNode.keySet.remove(key)
        if len(curNode.keySet) == 0:
            self.removeNodeFromList(curNode)
            self.cntKey.pop(curNode.cnt)
    # 刪掉curNode節點
    def removeNodeFromList(self, curNode):
        curNode.prev.next = curNode.next
        curNode.next.prev = curNode.prev
        curNode.next = None
        curNode.prev = None

433. 最小基因變化

# 雙向dfs
class Solution:
    def minMutation(self, start: str, end: str, bank: List[str]) -> int:
        if end not in bank: return -1
        start_set = {start}
        end_set = {end}
        bank = set(bank)
        length = 0
        change_map = {'A': 'TCG', 'T': 'ACG', 'C': 'ATG', 'G': 'ATC'}
        while start_set:
            length += 1
            new_set = set()
            for node in start_set:
                for i, s in enumerate(node):
                    for c in change_map[s]:
                        new = node[:i] + c + node[i + 1:]
                        if new in end_set:
                            return length
                        if new in bank:
                            new_set.add(new)
                            bank.remove(new)
            start_set = new_set
            if len(end_set) < len(start_set):
                start_set, end_set = end_set, start_set
        return -1

434. 字符串中的單詞數

class Solution:
    def countSegments(self, s: str) -> int:
        return len(s.split())

435. 無重疊區間

# 貪心
class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        intervals.sort(key=lambda x: x[1])
        cur_end = float("-inf")
        num = 0
        for start, end in intervals:
            if start >= cur_end:
                num += 1
                cur_end = end
        return len(intervals) - num

436. 尋找右區間

# 雙指針
class Solution:
    def findRightInterval(self, intervals: List[List[int]]) -> List[int]:
        n = len(intervals)
        intervals = [tuple(interval) for interval in intervals]
        res = [-1] * n
        loc = {}
        for idx, val in enumerate(intervals):
            loc[val] = idx
        left_sort = sorted(intervals)
        right_sort = sorted(intervals, key=lambda x: x[1])
        i = 0
        j = 0
        while i < n:
            while j < n and right_sort[j][1] <= left_sort[i][0]:
                res[loc[right_sort[j]]] = loc[left_sort[i]] 
                j += 1
            else:
                i += 1
        return res

437. 路徑總和 III

# 前綴和
class Solution:
    def pathSum(self, root: TreeNode, _sum: int) -> int:
        from collections import defaultdict
        prefix = defaultdict(int)
        # 前綴和的個數
        prefix[0] = 1
        res = 0
        def dfs(root, cur):
            nonlocal res
            if not root: return
            cur += root.val
            target = cur - _sum
            res += prefix[target]
            prefix[cur] += 1
            dfs(root.left, cur)
            dfs(root.right, cur)
            # 回溯
            prefix[cur] -= 1
        dfs(root, 0)
        return res

438. 找到字符串中所有字母異位詞

# 滑動窗口
class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        # 記錄p, s字母個數
        p_count = [0] * 26
        s_count = [0] * 26
        res = []
        for a in p:
            p_count[ord(a) - 97] += 1
        left = 0
        for right in range(len(s)):
            if right < len(p) - 1:
                s_count[ord(s[right]) - 97] += 1
                continue
            # 窗口加一個, 減一個,維護長度爲len(p)的長度
            s_count[ord(s[right]) - 97] += 1
            if p_count == s_count:
                res.append(left)
            s_count[ord(s[left]) - 97] -= 1
            left += 1
        return res

440. 字典序的第K小數字

# 十叉樹
class Solution:
    def findKthNumber(self, n: int, k: int) -> int:
        def cal_steps(n, n1, n2):
            step = 0
            while n1 <= n:
                step += min(n2, n + 1) - n1
                n1 *= 10
                n2 *= 10
            return step
        res = 1
        k -= 1
        while k > 0:
            steps = cal_steps(n, res, res + 1)
            if steps <= k:
                k -= steps
                res += 1
            else:
                k -= 1
                res *= 10
        return res
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章