Leecode周赛 222 [前缀和、LCS]

5641. 卡车上的最大单元数

请你将一些箱子装在 一辆卡车 上。给你一个二维数组 boxTypes ,其中 boxTypes[i] = [numberOfBoxesi, numberOfUnitsPerBoxi] :

numberOfBoxesi 是类型 i 的箱子的数量。
numberOfUnitsPerBoxi 是类型 i 每个箱子可以装载的单元数量。
整数 truckSize 表示卡车上可以装载 箱子 的 最大数量 。只要箱子数量不超过 truckSize ,你就可以选择任意箱子装到卡车上。

返回卡车可以装载 单元 的 最大 总数。

示例 1:

输入:boxTypes = [[1,3],[2,2],[3,1]], truckSize = 4
输出:8
解释:箱子的情况如下:

  • 1 个第一类的箱子,里面含 3 个单元。
  • 2 个第二类的箱子,每个里面含 2 个单元。
  • 3 个第三类的箱子,每个里面含 1 个单元。
    可以选择第一类和第二类的所有箱子,以及第三类的一个箱子。
    单元总数 = (1 * 3) + (2 * 2) + (1 * 1) = 8

示例 2:

输入:boxTypes = [[5,10],[2,5],[4,7],[3,9]], truckSize = 10
输出:91

Note

  1. 签到: 排序 嗯找, o(nlogn)

Code

class Solution:
    def maximumUnits(self, boxTypes: List[List[int]], truckSize: int) -> int:
        temp = sorted(boxTypes,key=lambda x: x[1])
        temp = temp[::-1]
        i = 0; cnt = 0
        ans = 0

        while(cnt < truckSize):
            if(cnt + temp[i][0] < truckSize):
                cnt += temp[i][0]
                ans += temp[i][0] * temp[i][1]
                
                i += 1
            else:
                ans += (truckSize - cnt) * temp[i][1]
                break
            if(i == len(temp)):
                break
                
       
        return ans

5642. 大餐计数

大餐 是指 恰好包含两道不同餐品 的一餐,其美味程度之和等于 2 的幂。

你可以搭配 任意 两道餐品做一顿大餐。

给你一个整数数组 deliciousness ,其中 deliciousness[i] 是第 i​​​​​​​​​​​​​​ 道餐品的美味程度,返回你可以用数组中的餐品做出的不同 大餐 的数量。结果需要对 109 + 7 取余。

注意,只要餐品下标不同,就可以认为是不同的餐品,即便它们的美味程度相同。

示例 1:

输入:deliciousness = [1,3,5,7,9]
输出:4
解释:大餐的美味程度组合为 (1,3) 、(1,7) 、(3,5) 和 (7,9) 。
它们各自的美味程度之和分别为 4 、8 、8 和 16 ,都是 2 的幂。

示例 2:

输入:deliciousness = [1,1,1,3,3,3,7]
输出:15
解释:大餐的美味程度组合为 3 种 (1,1) ,9 种 (1,3) ,和 3 种 (1,7) 。

提示:

1 <= deliciousness.length <= 105
0 <= deliciousness[i] <= 220

Note1

  1. defalutdict记录每个元素的出现的次数,a + b = target, 遍历的a的时候更新dic,遍历到b的时候计数增加,时间o(22n), 空间o(n)

Code1

class Solution:
    def countPairs(self, deliciousness: List[int]) -> int:
        ans=0
        mod=10**9+7
        counter = defaultdict(int)
        for d in deliciousness:
           # print(counter)
            for i in range(22):
                find = 2**i - d 
                if find in counter:
                    ans += counter[find] % mod
            counter[d] += 1
       # print(counter)
        return ans % mod

5643. 将数组分成三个子数组的方案数

我们称一个分割整数数组的方案是 好的 ,当它满足:

数组被分成三个 非空 连续子数组,从左至右分别命名为 left , mid , right 。
left 中元素和小于等于 mid 中元素和,mid 中元素和小于等于 right 中元素和。
给你一个 非负 整数数组 nums ,请你返回 好的 分割 nums 方案数目。由于答案可能会很大,请你将结果对 109 + 7 取余后返回。

示例 1:

输入:nums = [1,1,1]
输出:1
解释:唯一一种好的分割方案是将 nums 分成 [1] [1] [1] 。

示例 2:

输入:nums = [1,2,2,2,5,0]
输出:3
解释:nums 总共有 3 种好的分割方案:
[1] [2] [2,2,5,0]
[1] [2,2] [2,5,0]
[1,2] [2,2] [5,0]

示例 3:

输入:nums = [3,2,1]
输出:0
解释:没有好的分割方案。

Note1

  1. 前缀和 + 二分查找

Code1

class Solution:
    def waysToSplit(self, nums: List[int]) -> int:
        if(len(nums) < 3): return 0
        p = 1;q = 2;cnt = 0;temp = 0
        pre = [0]
        n = len(nums)
        for i in range(len(nums)):
            temp += nums[i]
            pre.append(temp)
        for i in range(1, n-1):
            first = pre[i]
            second_least = max(i+1, bisect.bisect_left(pre,2 * first))
            second_most = min(n, bisect.bisect_right(pre,(pre[-1] - first) // 2 + first))
            #print(second_least, second_most)
            if(second_most > second_least):
                cnt += (second_most - second_least) %  (10 ** 9 + 7)
        cnt = cnt  %  (10 ** 9 + 7)
        return cnt

5644. 得到子序列的最少操作次数

给你一个数组 target ,包含若干 互不相同 的整数,以及另一个整数数组 arr ,arr 可能 包含重复元素。

每一次操作中,你可以在 arr 的任意位置插入任一整数。比方说,如果 arr = [1,4,1,2] ,那么你可以在中间添加 3 得到 [1,4,3,1,2] 。你可以在数组最开始或最后面添加整数。

请你返回 最少 操作次数,使得 target 成为 arr 的一个子序列。

一个数组的 子序列 指的是删除原数组的某些元素(可能一个元素都不删除),同时不改变其余元素的相对顺序得到的数组。比方说,[2,7,4] 是 [4,2,3,7,2,1,4] 的子序列(加粗元素),但 [2,4,2] 不是子序列。

示例 1:

输入:target = [5,1,3], arr = [9,4,2,3,4]
输出:2
解释:你可以添加 5 和 1 ,使得 arr 变为 [5,9,4,1,2,3,4] ,target 为 arr 的子序列。
示例 2:

输入:target = [6,4,8,1,3,2], arr = [4,7,6,2,3,8,6,1]
输出:3

提示:

1 <= target.length, arr.length <= 105
1 <= target[i], arr[i] <= 109
target 不包含任何重复元素。

Note1

  1. 进阶版的最长上升子序列( 最长上升子序列链接) nlogn的方法才可以,从这便可以看出,刷完题看题解的重要性
  2. 普通的最长上升子序列,需要o(n^2) dp[i] = dp[j] +1 寻找i的部分无法优化,但寻找j的部分可以再做改进
  3. 最长子序列题目总结:
    1. 无重复字符的最长子串
    2. 最大子序和
  4. 题目思路:把arr 在 list里出现的下标,当做最长子序列题目的nums,立马双百!

Code1 最长上升子序列的nlogn解法

方法讲解

def lengthOfLIS(self, nums: List[int]) -> int:
        size = len(nums)
        if size < 2: return size
        tail = [nums[0]]
        for i in range(1, size):
            left = bisect.bisect_left(tail,nums[i])
            if left == len(tail):
                tail.append(nums[i])
            else:
                tail[left] = nums[i]
        return len(tail)

Code2

class Solution:
    def minOperations(self, target: List[int], arr: List[int]) -> int:
        dic = defaultdict(int)
        if(len(arr) < 1 or len(target)< 1): return len(target)
        xu = []
        for i in range(len(target)):
            dic[target[i]] = i + 1
        for i in range(len(arr)):
            if(dic[arr[i]] != 0):
                xu.append(dic[arr[i]] - 1)
        tail = [xu[0]]
        for i in range(1, len(xu)):
            left = bisect.bisect_left(tail,xu[i])
            if(left == len(tail)):
                tail.append(xu[i])
            else:
                tail[left] = xu[i]
        return len(target) - len(tail)

你可能感兴趣的:(LeetCode)