【力扣roadmap】3479. 水果成篮 III

14 阅读3分钟

题目描述

image.png

思路

这道题说实话没啥可讲的,你只要会线段树维护区间最大值,就OK了。

题目要求必须在数组中找到第一个大于等于目标的位置,然后将其作废(更新成非法值)。如果找不到任何大于等于目标的位置,答案加一。

这里稍微讲一下单点修改吧。线段树的单点修改好像没什么模板代码,也不如区间修改受到重视,因为线段树的区间修改会涉及到懒标记。

本题的单点修改,代码主体和query差不多,你需要找到目标idx : 找到目标点然后更新其mx值,返回1表示已经修改完毕; 区间情况下,先往左子树找,如果左子树返回了1,说明左子树完成了单点修改,只需要更新本节点mx值后将这个1向上传递即可;如果左子树返回了0,说明左子树没找到目标idx,再去右子树找找。

因为我们是query到目标下标,这个位置就作废了,所以我们之间干脆找到这个目标idx后立即将其mx置成非法值算了。然后你query的剩余代码注意在每次return前刷一下mx值就成功将单点update和query两个函数合并了。

代码

update和query职责分离写法,代码更清晰

class Solution:
    def numOfUnplacedFruits(self, fruits: List[int], baskets: List[int]) -> int:
        # 找到区间第一个满足的值 然后将其更新成-1 
        # 找不到满足的值 那就答案+1
        n = len(baskets)
        mx = [0] * (4 * n + 1)
        def build(p: int , l : int , r : int) :
            if l == r :
                mx[p] = baskets[l]
                return 
            mid = l + (r - l) // 2 
            build(p * 2 , l , mid) 
            build(p * 2 + 1 , mid + 1 , r) 
            mx[p] = max(mx[ p * 2 ] , mx[p * 2 + 1])

        def query(p : int , l : int , r : int , target : int) -> int :
            if mx[p] < target : # 该区间没有满足要求的位置
                return -1 
            if l == r :
                return l
            mid = l + ( r - l ) // 2
            l_ret = query(p * 2 , l , mid , target) 
            if l_ret != -1 :
                return l_ret
            return query( p * 2 + 1 , mid + 1 , r , target) 
         
        def update(p : int , l : int , r : int , target_idx : int) -> int : # 单点修改
            if target_idx < l or r < target_idx : # 目标不在区间内
                return 0
            if l == r == target_idx : # 找到目标
                mx[p] = -1 
                return 1
            mid = l + (r - l) // 2 
            l_update = update(p * 2 , l , mid , target_idx) # 优先修改左子树
            if l_update == 1 : # 发现修改成功 直接更新mx返回
                mx[p] = max(mx[p * 2] , mx[p * 2 + 1])
                return l_update
            r_update = update(p * 2 + 1 , mid + 1 , r , target_idx)  # 左子树更新失败 只能去更新右子树
            mx[p] = max(mx[p * 2] , mx[p * 2 + 1])
            return r_update  # 左子树更新失败 右子树一定能更新成功


        build(1,0,n-1)
        ans = 0 
        for q in fruits :
            ret = query(1,0,n-1,q) 
            if ret != -1 :
                update(1,0,n-1,ret) 
            else :
                ans += 1 
        return ans 

update和query合并的写法,跑起来更快

class Solution:
    def numOfUnplacedFruits(self, fruits: List[int], baskets: List[int]) -> int:
        # 找到区间第一个满足的值 然后将其更新成-1 
        # 找不到满足的值 那就答案+1
        n = len(baskets)
        mx = [0] * (4 * n + 1)
        def build(p: int , l : int , r : int) :
            if l == r :
                mx[p] = baskets[l]
                return 
            mid = l + (r - l) // 2 
            build(p * 2 , l , mid) 
            build(p * 2 + 1 , mid + 1 , r) 
            mx[p] = max(mx[ p * 2 ] , mx[p * 2 + 1])

        def query(p : int , l : int , r : int , target : int) -> int :
            if mx[p] < target : # 该区间没有满足要求的位置
                return -1 
            if l == r :
                mx[p] = -1 
                return l
            mid = l + ( r - l ) // 2
            l_ret = query(p * 2 , l , mid , target) 
            if l_ret != -1 :
                mx[p] = max(mx[ p * 2 ] , mx[p * 2 + 1])
                return l_ret
            r_ret = query( p * 2 + 1 , mid + 1 , r , target) 
            mx[p] = max(mx[ p * 2 ] , mx[p * 2 + 1])
            return r_ret


        build(1,0,n-1)
        ans = 0 
        for q in fruits :
            ret = query(1,0,n-1,q) 
            if ret == -1 :
                ans += 1 
        return ans