【周赛总结】第193场周赛——制作花(合并选取区间),树节点的第 K 个祖先

2020/06/14 rank 1173/3803 ac 2

引言

状态不是很好,这周只a了两道题,思路不畅。

制作m束花的天数

【周赛总结】第193场周赛——制作花(合并选取区间),树节点的第 K 个祖先_第1张图片

首先想到采用二分的方法,核心在于注意到题目的解具有单调性,也就是说,在第i天可以,则在之后的第i+1天也是都可以的。

class Solution:
    def minDays(self, bloomDay: List[int], m: int, k: int) -> int:
        ## 二分的方法
        right = max(bloomDay)
        left = 1

        def valid(mid):
            flower = 0
            need = m
            for i in range(len(bloomDay)):
                if bloomDay[i]<=mid:
                    flower += 1
                else:
                    need -= flower//k
                    flower = 0
            need -= flower//k
            return need<=0

        while left<=right:
            mid = left+(right-left)//2
            if valid(mid):
                right = mid-1
            else:
                left = mid+1
        if left>max(bloomDay):
            return -1
        return left

另外一个方法是我在答题时候的思路,但是考场上没有能做出来。也就是利用字典,维护区间的算法。其实很类似于并查集。利用两个字典维护每一个连续数组的左右边界。

需要注意,字典r是维护了一个右侧连续数组的右端点,l维护了一个左侧连续数组的左端点。

class Solution(object):
    def minDays(self, bloomDay, m, k):
        """
        :type bloomDay: List[int]
        :type m: int
        :type k: int
        :rtype: int
        """
        ## 区间合并的算法
        days = []
        for i in range(len(bloomDay)):
            days.append([bloomDay[i], i])
        days.sort(key = lambda x:x[0])
        r = {}
        l = {}
        sum_ = 0

        def get(left, right):
            return (right-left+1)//k

        for day,index in days:
            if index-1 in l and index+1 in r:
                sum_ = sum_ - get(l[index-1],index-1) - get(index+1,r[index+1]) + get(l[index-1],r[index+1]) 
                ## 这一步的更新需要注意,更改最左边位置的右界限和最右边位置的左边界。
                r[l[index-1]] = r[index+1]
                l[r[index+1]] = l[index-1]
            elif index-1 in l:
                sum_ = sum_ - get(l[index-1],index-1) + get(l[index-1],index)
                r[l[index-1]] = index
                l[index] = l[index-1]
            elif index+1 in r:
                sum_ = sum_- get(index+1,r[index+1]) + get(index,r[index+1])
                l[r[index+1]] = index
                r[index] = r[index+1]
            else:
                r[index] = index
                l[index] = index
                sum_ += get(index,index)
            print(sum_)
            if sum_ >=m:
                return day
        return -1

树上倍增

【周赛总结】第193场周赛——制作花(合并选取区间),树节点的第 K 个祖先_第2张图片【周赛总结】第193场周赛——制作花(合并选取区间),树节点的第 K 个祖先_第3张图片

树上倍增算法

class TreeAncestor:

    def __init__(self, n: int, parent: List[int]):
        self.cols = 20      # log(50000) < 20

        self.dp = [[-1] * self.cols for _ in range(n)]
        for i in range(n):
            self.dp[i][0] = parent[i]

        # 动态规划设置祖先, dp[node][j] 表示 node 往前推第 2^j 个祖先
        for j in range(1, self.cols):
            for i in range(n):
                if self.dp[i][j-1] != -1:
                    self.dp[i][j] = self.dp[self.dp[i][j-1]][j-1]
        return

    def getKthAncestor(self, node: int, k: int) -> int:
        for i in range(self.cols - 1, -1, -1):
            if k & (1 << i):
                node = self.dp[node][i]
                if node == -1:
                    break
        return node


# Your TreeAncestor object will be instantiated and called as such:
# obj = TreeAncestor(n, parent)
# param_1 = obj.getKthAncestor(node,k)

你可能感兴趣的:(周赛总结)