LeetCode - 相同子树替换后最长重复子串多米诺骨牌

Posted SpikeKing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode - 相同子树替换后最长重复子串多米诺骨牌相关的知识,希望对你有一定的参考价值。

多米诺骨牌

838. 推多米诺,注意多米诺骨牌是连续倒,直到停止。

考察

  1. 先入先出队列(deque),处理时序问题。
  2. 时序数组和状态数组
#!/usr/bin/env python
# -- coding: utf-8 --
"""
Copyright (c) 2022. All rights reserved.
Created by C. L. Wang on 2022/5/31
"""

from collections import deque


class Solution:
    def pushDominoes(self, dominoes: str) -> str:
        n = len(dominoes)
        # 使用[]会超时,只能使用deque
        queue = deque()
        time = [-1] * n  # 模拟当前时刻, -1游戏未开始
        force = [[] for _ in range(n)]  # 保存当前点受力

        # 初始化, 即0时刻, 状态
        for i, f in enumerate(dominoes):
            if f != ".":
                queue.append(i)
                time[i] = 0
                force[i].append(f)

        res = ["."] * n
        while queue:
            i = queue.popleft()
            # 只有1个受力, 如果有2个受力, 该点一定不动, LR和RL都是如此
            if len(force[i]) == 1:
                res[i] = f = force[i][0]  # 结果确定
                ni = i - 1 if f == 'L' else i + 1  # L向左,R向右
                if 0 <= ni < n:
                    t = time[i]
                    if time[ni] == -1:  # 第1次受到作用力
                        queue.append(ni)
                        time[ni] = t + 1
                        force[ni].append(f)
                    elif time[ni] == t + 1:  # 如果同时受到作用力, 被改变
                        force[ni].append(f)
        return ''.join(res)


def main():
    so = Solution()
    res = so.pushDominoes(".L.R.....LR..L..")
    print("res: ".format(res))  # LL.RRR.LLLRRLL..


if __name__ == '__main__':
    main()

替换后最长重复子串

424. 替换后的最长重复字符

考察:

  1. 双指针的用法
  2. 滑动窗口长度,满足条件,则递增,不满足条件,则不变
  3. 辅助变量,最大出现次数,只保存最大值,单调递增
  4. 统计窗口中出现值的次数。
class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        """
        424. 替换后的最长重复字符
        时间复杂度O(n),遍历1次
        空间复杂度O(C),C是字符集

        通过双指针的滑动窗口进行确定
        统计窗口中每个字母的出现次数,获取最大出现次数
        比较:字符串长度的关系 与 最大出现次数 + k

        维护历史最大值的原因:窗口从根本来说是只增不减的:
        如果k够用来替换的话,right右移1步,窗口变大(当前维护的最大值变大,不消耗k;当前维护的最大值不变,将消耗k);
        如果k不够用来替换的话,left和right都右移一步,窗口不变(我们已经不关心比当前小的情况了)。
        """
        if not s:
            return 0

        # 窗口中的出现次数
        num = [0] * 26  # 26个大写字母
        n = len(s)
        maxn, left, right = 0, 0, 0

        # 以右指针为基准
        while right < n:
            rc = ord(s[right]) - ord("A")
            lc = ord(s[left]) - ord("A")
            num[rc] += 1  # 求窗口中曾出现某字母的最大次数
            maxn = max(maxn, num[rc])  # 最大出现次数,递增
            s_len = right - left + 1  # 字符串长度
            if s_len > k + maxn:  # 不满足条件
                num[lc] -= 1
                left += 1
            right += 1  # 遍历
        return right - left


def main():
    so = Solution()
    res = so.characterReplacement("AACBAKBBA", 2)
    print("res: ".format(res))  # 5,替换CB为AA


if __name__ == '__main__':
    main()

相同题目:2024. 考试的最大困扰度

class Solution:
    def maxConsecutiveAnswers(self, answerKey: str, k: int) -> int:
        """
        参考: 424. 替换后的最长重复字符
        双指针遍历一次
        时间复杂度:O(N)
        空间复杂度:O(N),存储次数的数组
        """
        if not answerKey:
            return 0
        nums = [0] * 2
        maxn, left, right = 0, 0, 0
        n = len(answerKey)
        while right < n:
            rk = 0 if answerKey[right] == "T" else 1
            nums[rk] += 1
            maxn = max(maxn, nums[rk])
            if right-left+1 > maxn + k:
                lk = 0 if answerKey[left] == "T" else 1
                nums[lk] -= 1
                left += 1
            right += 1
        return right - left


def main():
    so = Solution()
    res = so.maxConsecutiveAnswers("TTFTTFFTT", 1)
    print("res: ".format(res))  # 5,替换第3个F为T


if __name__ == '__main__':
    main()

相同子树

652. 寻找重复的子树

树:[1,2,3,4,null,2,4,null,null,4],注意最后一层只有非空节点,才有null值

考察:

  1. 构建二叉树,二叉树是含义叶子节点的满二叉树,需要判断非空节点。
  2. 遍历二叉树,也需要去除最后的连续空值。
  3. 考察字典的用法。

构建和遍历,细节较多。

import collections


# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


def build_tree(alist):
    """
    构建二叉树
    """
    n = len(alist)
    root = TreeNode(alist[0])
    queue = [root]
    i = 1
    while queue:
        cur = queue.pop(0)
        if cur:
            if i < n and alist[i]:  # 非空节点加入
                cur.left = TreeNode(alist[i])
                queue.append(cur.left)
            i += 1
            if i < n and alist[i]:  # 非空节点加入
                cur.right = TreeNode(alist[i])
                queue.append(cur.right)
            i += 1
    return root


def tree2list(root):
    """
    树转换为list
    """
    res = []
    queue = [root]
    while queue:
        node = queue.pop(0)
        res.append(node.val)
        if not node.val:  # 空节点
            continue
        if node.left:
            queue.append(node.left)
        else:
            queue.append(TreeNode(None))
        if node.right:
            queue.append(node.right)
        else:
            queue.append(TreeNode(None))
    # 去除最后的None
    last = 0
    for i, val in enumerate(res):
        if val:
            last = i
    return res[:last+1]


class Solution:
    def findDuplicateSubtrees(self, root):
        """
        652. 寻找重复的子树
        字典 + 元组,递归遍历左右节点
        时间复杂度:O(N),其中N二叉树上节点的数量,每个节点都需要访问一次。
        空间复杂度:O(N),每棵子树的存储空间都为 O(1)。
        """
        if not root:
            return []
        # 相当于给每个元组一个固定编号,从1开始,依次排列
        # 也可以不适用,则耗时变长
        uid_dict = collections.defaultdict()
        uid_dict.default_factory = uid_dict.__len__  # 第1个元组是1,之后依次排列

        count = collections.defaultdict(int)  # 统计出现次数
        res = []  # 保存结果
        def lookup(node):
            if not node:
                return
            # uid = (node.val, lookup(node.left), lookup(node.right))  # 唯一的uid
            uid = uid_dict[(node.val, lookup(node.left), lookup(node.right))]
            count[uid] += 1
            if count[uid] == 2:
                res.append(node)
            return uid
        lookup(root)
        return res


def main():
    root_list = [1, 2, 3, 4, None, 2, 4, None, None, 4]
    print("input: ".format(root_list))
    root = build_tree(root_list)
    print("show: ".format(tree2list(root)))
    so = Solution()
    res = so.findDuplicateSubtrees(root)
    print("res: ".format([tree2list(r) for r in res]))  # [[4], [2, 4]]


if __name__ == '__main__':
    main()

以上是关于LeetCode - 相同子树替换后最长重复子串多米诺骨牌的主要内容,如果未能解决你的问题,请参考以下文章

[LeetCode] 424. Longest Repeating Character Replacement

Leetcode(无重复字符的最长子串;删除排序链表中的重复元素II;加一;最后一个单词的长度;相同的树)

LeetCode-003-无重复字符的最长子串

Leetcode——最长重复数组(最长公共子串) / 最长重复子串

LeetCode 无重复字符的最长子串

leetcode题解#3:无重复字符的最长子串