题目描述
思路
这道题说实话没啥可讲的,你只要会线段树维护区间最大值,就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