[LeetCode周赛复盘] 第 353 场周赛20230709

[LeetCode周赛复盘] 第 353 场周赛20230709

    • 一、本周周赛总结
    • 6451. 找出最大的可达成数字
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 6899. 达到末尾下标所需的最大跳跃次数
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 6912. 构造最长非递减子数组
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 6919. 使数组中的所有元素都等于零
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 参考链接

一、本周周赛总结

  • 感觉有奖品大家都来了。
  • T1 数学。
  • T2 dp。
  • T3 dp。
  • T4 差分/BIT RUPQ。
    [LeetCode周赛复盘] 第 353 场周赛20230709_第1张图片

6451. 找出最大的可达成数字

6451. 找出最大的可达成数字

1. 题目描述

[LeetCode周赛复盘] 第 353 场周赛20230709_第2张图片

2. 思路分析

  • 为了使x num在t步内相同,需要相向而行,每步最大缩短距离是2,那么t步距离是2t。

3. 代码实现

class Solution:
    def theMaximumAchievableX(self, num: int, t: int) -> int:
        return num+2*t

6899. 达到末尾下标所需的最大跳跃次数

6899. 达到末尾下标所需的最大跳跃次数

1. 题目描述

[LeetCode周赛复盘] 第 353 场周赛20230709_第3张图片

2. 思路分析

  • 每个位置都尝试向后跳即可。
  • 思考,如果n<=1e5咋做?
    • 改成填表法,然后用离散化线段树维护前边的max。
    • 要离散的数据是nums里所有v v-t v+t。
    • 这题由于n小,所以用BIT甚至更快。

3. 代码实现

class Solution:
    def maximumJumps(self, nums: List[int], t: int) -> int:
        n = len(nums)
        f = [-inf]*n 
        f[0] = 0 
        for i in range(n-1):
            for j in range(i+1,n):
                if abs(nums[j]-nums[i]) <= t:
                    f[j] = max(f[j],f[i]+1)
           
        return f[-1] if f[-1] > -inf else -1

nlgn线段树做法


class ZKW:
    # n = 1
    # size = 1
    # log = 2
    # d = [0]
    # op = None
    # e = 10 ** 15
    """自低向上非递归写法线段树,0_indexed
    tmx = ZKW(pre, max, -2 ** 61)
    """
    __slots__ = ('n', 'op', 'e', 'log', 'size', 'd')

    def __init__(self, V, OP, E):
        """
        V: 原数组
        OP: 操作:max,min,sum
        E: 每个元素默认值
        """
        self.n = len(V)
        self.op = OP
        self.e = E
        self.log = (self.n - 1).bit_length()
        self.size = 1 << self.log
        self.d = [E for i in range(2 * self.size)]
        for i in range(self.n):
            self.d[self.size + i] = V[i]
        for i in range(self.size - 1, 0, -1):
            self.update(i)

    def set(self, p, x):
        # assert 0 <= p and p < self.n
        update = self.update
        p += self.size
        self.d[p] = x
        for i in range(1, self.log + 1):
            update(p >> i)

    def get(self, p):
        # assert 0 <= p and p < self.n
        return self.d[p + self.size]

    def query(self, l, r):  # [l,r)左闭右开
        # assert 0 <= l and l <= r and r <= self.n
        sml, smr, op, d = self.e, self.e, self.op, self.d

        l += self.size
        r += self.size

        while l < r:
            if l & 1:
                sml = op(sml, d[l])
                l += 1
            if r & 1:
                smr = op(d[r - 1], smr)
                r -= 1
            l >>= 1
            r >>= 1
        return self.op(sml, smr)

    def all_query(self):
        return self.d[1]

    def max_right(self, l, f):
        """返回l右侧第一个不满足f的位置"""
        # assert 0 <= l and l <= self.n
        # assert f(self.e)
        if l == self.n:
            return self.n
        l += self.size

        sm, op, d, size = self.e, self.op, self.d, self.size
        while True:
            while l % 2 == 0:
                l >>= 1
            if not (f(op(sm, d[l]))):
                while l < size:
                    l = 2 * l
                    if f(op(sm, d[l])):
                        sm = op(sm, d[l])
                        l += 1
                return l - size
            sm = op(sm, d[l])
            l += 1
            if (l & -l) == l:
                break
        return self.n

    def min_left(self, r, f):
        """返回r左侧连续满足f的最远位置的位置"""
        # assert 0 <= r and r < self.n
        # assert f(self.e)
        if r == 0:
            return 0
        r += self.size
        sm, op, d, size = self.e, self.op, self.d, self.size

        while True:
            r -= 1
            while r > 1 and (r % 2):
                r >>= 1
            if not (f(op(d[r], sm))):
                while r < size:
                    r = (2 * r + 1)
                    if f(op(d[r], sm)):
                        sm = op(d[r], sm)
                        r -= 1
                return r + 1 - size
            sm = op(d[r], sm)
            if (r & -r) == r:
                break
        return 0

    def update(self, k):
        self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])

    def __str__(self):
        return str([self.get(i) for i in range(self.n)])



class Solution:
    def maximumJumps(self, nums: List[int], t: int) -> int:
        n = len(nums)
        h = set(nums)
        for v in nums:
            h.add(v-t)
            h.add(v+t)
        h = sorted(h)
        size = len(h)
        f = ZKW([-inf]*size,max,-inf)
        f.set(bisect_left(h,nums[0]),0)
        for i in range(1,n):            
            l,r = bisect_left(h,nums[i]-t),bisect_right(h,nums[i]+t)
            i = bisect_left(h,nums[i])           
            ans = max(f.get(i), f.query(l,r)+1)
            f.set(i,ans)
            
           
        return [-1,ans][ans>-inf]

6912. 构造最长非递减子数组

6912. 构造最长非递减子数组

1. 题目描述

[LeetCode周赛复盘] 第 353 场周赛20230709_第4张图片

2. 思路分析

  • dp。
  • 定义f[i][0/1]为以i为右端点时,分别使用num1 num2中数字时的最长长度。
  • 那么转移分别讨论前一个数大小即可。
  • 实现时可以省去第一维度。

3. 代码实现

class Solution:
    def maxNonDecreasingLength(self, nums1, nums2):
        n = len(nums1)        
        
        x = y = 1
        ans = 1 
        for i in range(1,n):
            a=b=1
            if nums1[i] >= nums1[i-1]:
                a = x+1
            if nums1[i] >= nums2[i-1]:
                a = max(a,y+1)
            
            if nums2[i] >= nums1[i-1]:
                b = x+1
            if nums2[i] >= nums2[i-1]:
                b = max(b,y+1)
            ans = max(ans,a,b)
            x,y = a,b 
        
        return ans

6919. 使数组中的所有元素都等于零

6919. 使数组中的所有元素都等于零

1. 题目描述

[LeetCode周赛复盘] 第 353 场周赛20230709_第5张图片

2. 思路分析

  • 一眼RUPQ,且是顺序的,所以强行写差分wa半天。
  • 早知道直接BIT了。

3. 代码实现

差分

class Solution:
    def checkArray(self, nums: List[int], k: int) -> bool:
        n = len(nums)
        d = [0]*(n+1)
        d[0] = nums[0]
        for i in range(1,n):
            d[i] = nums[i] - nums[i-1]
       
        for i in range(n-k+1):
            # print(i)
            if d[i]<0:
                # print(i,d[i])
                return False
            
            d[i+k] += d[i]
            d[i]-=d[i]
        # print(d)
        if all(v==0 for v in d[:-1])  :
            return True 
        return False            

BIT

class BinIndexTreeRUPQ:
    """树状数组的RUPQ模型,结合差分理解"""
    def __init__(self, size_or_nums):  # 树状数组,下标需要从1开始
        # 如果size 是数字,那就设置size和空数据;如果size是数组,那就是a
        if isinstance(size_or_nums, int):
            self.size = size_or_nums
            self.c = [0 for _ in range(self.size + 5)]
        else:
            self.size = len(size_or_nums)
            self.c = [0 for _ in range(self.size + 5)]
            for i, v in enumerate(size_or_nums):
                self.add_interval(i + 1, i + 1, v)

    def add_point(self, i, v):  # 单点增加,下标从1开始;不支持直接调用,这里增加的是差分数组的单点
        while i <= self.size:
            self.c[i] += v
            i += i&-i

    def sum_prefix(self, i):  # 前缀求和,下标从1开始;不支持直接调用,这里求和的是差分数组的前缀和
        s = 0
        while i >= 1:
            s += self.c[i]
            i &= i-1
        return s

    def add_interval(self, l, r, v):  # 区间加,下标从1开始,把[l,r]闭区间都加v
        self.add_point(l, v)
        self.add_point(r + 1, -v)

    def query_point(self, i):  # 单点询问值,下标从1开始,返回i位置的值
        return self.sum_prefix(i)

    def lowbit(self, x):
        return x & -x
class Solution:
    def checkArray(self, nums: List[int], k: int) -> bool:
        n = len(nums)
        bit = BinIndexTreeRUPQ(nums)
        for i in range(n-k+1):
            p = bit.query_point(i+1)
            if p < 0:
                return False 
            bit.add_interval(i+1,i+k,-p)
        if all(bit.query_point(i)==0 for i in range(1,n+1))  :
            return True 
        return False                  

参考链接

你可能感兴趣的:(力扣周赛复盘,leetcode,算法,职场和发展)