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

猜你喜欢

转载自blog.csdn.net/weixin_44604541/article/details/106920834