【Leetcode】699. Falling Squares 699. 掉落的方块

1
2
3

解法

要说难其实也不难…… O ( n 2 ) O(n^2) O(n2)的方法都可以过

解法一:暴力

每放下一个方块,记录一下放下后这个方块顶端高度,它由两部分组成:一是方块自己的高度,二是以前放下的与该方块相交的方块的顶端高度的最大值,由这两部分相加构成
得到每个方块放下时的顶端高度之后,最后的ans数组就是这个高度数组的前缀最大值数组

class Solution(object):
    def fallingSquares(self, positions):
        """
        :type positions: List[List[int]]
        :rtype: List[int]
        """
        n = len(positions)
        ans = [None]*n
        for i in xrange(n):
            a,b = positions[i]
            ans[i] = b
            for j in xrange(i):
                c,d = positions[j]
                if max(a,c)<min(a+b,c+d):
                    ans[i] = max(ans[i],ans[j]+b)
        for i,a in enumerate(ans[1:]):
            ans[i+1] = max(ans[i],a)
        return ans

虽然慢,但是比较简单

解法二:离散化

其实这个问题又可以转变成求某区间最大值,以及更新某区间值的一个问题
而这样的问题只和区间端点有关
从题目条件看出,区间只有1000个,那不同的端点数值不会超过2000个
离散化之后再用上面的暴力就可以了

class Solution(object):
    def fallingSquares(self, positions):
        """
        :type positions: List[List[int]]
        :rtype: List[int]
        """
        values = sorted({x[0] for x in positions}|{x[0]+x[1]-1 for x in positions})
        n = len(values)
        idx = {}
        for i,c in enumerate(values):
            idx[c] = i
        heights = [0]*n
        ans = []
        def query(l,r):
            res = 0
            for i in xrange(idx[l],idx[r]+1):
                res = max(res,heights[i])
            return res
        def update(l,r,v):
            for i in xrange(idx[l],idx[r]+1):
                heights[i] = max(heights[i],v)
        for i,(x,y) in enumerate(positions):
            h = query(x,x+y-1)
            update(x,x+y-1,h+y)
            if i==0:
                ans.append(h+y)
            else:
                ans.append(max(h+y,ans[-1]))
        return ans

线段树+离散化

上面的更新查询操作其实完全就是线段树的设计,可以用线段树来实现

class ST(object):
    def __init__(self,n,uf,qf):
        self.n = n
        self.uf = uf
        self.qf = qf
        self.t = [0]*(n<<1)
        self.lazy = [0]*n
    
    def _apply(self,x,v):
        self.t[x] = self.uf(self.t[x],v)
        if x<self.n:
            self.lazy[x] = self.uf(self.lazy[x],v)
    
    def _pull(self,x):
        while x>1:
            x /= 2
            self.t[x] = self.qf(self.t[x<<1],self.t[(x<<1)+1])
            self.t[x] = self.uf(self.t[x],self.lazy[x])
    
    def update(self,l,r,v):
        l += self.n
        r += self.n
        l0,r0 = l,r
        while l<=r:
            if l&1:
                self._apply(l,v)
                l += 1
            if not r&1:
                self._apply(r,v)
                r -= 1
            l,r = l>>1,r>>1
        self._pull(l0)
        self._pull(r0)
    
    def _push(self,x):
        H = self.n.bit_length()
        for h in xrange(H,0,-1):
            y = x>>h
            if self.lazy[y]:
                self._apply(y<<1,self.lazy[y])
                self._apply((y<<1)+1,self.lazy[y])
                self.lazy[y] = 0
    
    def query(self,l,r):
        l += self.n
        r += self.n
        self._push(l)
        self._push(r)
        res = 0
        while l<=r:
            if l&1:
                res = self.qf(res,self.t[l])
                l += 1
            if not r&1:
                res = self.qf(res,self.t[r])
                r -= 1
            l,r = l>>1,r>>1
        return res
            

class Solution(object):
    def fallingSquares(self, positions):
        """
        :type positions: List[List[int]]
        :rtype: List[int]
        """
        values = sorted({x[0] for x in positions}|{x[0]+x[1]-1 for x in positions})
        n = len(values)
        idx = {}
        for i,c in enumerate(values):
            idx[c] = i
        t = ST(n,max,max)
        ans = []
        for x,y in positions:
            # print idx[x],idx[x+y-1]
            v = t.query(idx[x],idx[x+y-1])
            t.update(idx[x],idx[x+y-1],y+v)
            if ans:
                ans.append(max(ans[-1],v+y))
            else:
                ans.append(v+y)
        return ans
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值