LeetCode1590. 使数组和能被 P 整除 / 2383. 赢得比赛需要的最少训练时长 / 1605. 给定行和列的和求可行矩阵

1590. 使数组和能被 P 整除

2023.3.10 每日一题

题目描述

给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空),使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。

请你返回你需要移除的最短子数组的长度,如果无法满足题目要求,返回 -1 。

子数组 定义为原数组中连续的一组元素。

示例 1:

输入:nums = [3,1,4,2], p = 6
输出:1
解释:nums 中元素和为 10,不能被 p 整除。我们可以移除子数组 [4] ,剩余元素的和为 6 。

示例 2:

输入:nums = [6,3,5,2], p = 9
输出:2
解释:我们无法移除任何一个元素使得和被 9 整除,最优方案是移除子数组 [5,2] ,剩余元素为 [6,3],和为 9 。

示例 3:

输入:nums = [1,2,3], p = 3
输出:0
解释:和恰好为 6 ,已经能被 3 整除了。所以我们不需要移除任何元素。

示例 4:

输入:nums = [1,2,3], p = 7
输出:-1
解释:没有任何方案使得移除子数组后剩余元素的和被 7 整除。

示例 5:

输入:nums = [1000000000,1000000000,1000000000], p = 3
输出:0

提示:

1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
1 <= p <= 10^9

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/make-sum-divisible-by-p
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

数据范围很大,想到会超时,但是还是写了个相对暴力的解法
加了个限制条件j < i + minlen 好像很多的,最后虽然通过了全部例子,但是还是超时了

class Solution {
    public int minSubarray(int[] nums, int p) {
        //搞个前缀和,然后遍历所有子数组应该就行了吧
        int l = nums.length;
        int[] presum = new int[l + 1];
        for(int i = 1; i <= l; i++){
            presum[i] = (presum[i - 1] + nums[i - 1] % p) % p;
        }
        if(presum[l] % p == 0)
            return 0;
        
        int minlen = l;
        for(int i = 0; i < l; i++){
            for(int j = i + 1; j < i + minlen && j <= l; j++){
                if((presum[l] - (presum[j] - presum[i])) % p == 0){
                    minlen = Math.min(minlen, j - i);
                    break;
                }
            }
        }
        return minlen == l? -1 : minlen;
    }
}

设总和为s,那么要被p整除,就要减去s - np,就是要找到一个子数组,使得子数组之和等于s - np
问题在于n不确定是多少,所以无法通过滑动窗口的方式来做

var是Java10版本中新出的特性,用它来定义局部变量。使用var定义变量的语法:var 变量名 = 初始值;1 var 不是关键字,相当于一种动态类型,编译器根据变量所赋的值来推断类型。

class Solution {
    public int minSubarray(int[] nums, int p) {
        //搞个前缀和,然后遍历所有子数组应该就行了吧
        int l = nums.length;
        int[] presum = new int[l + 1];
        for(int i = 1; i <= l; i++){
            presum[i] = (presum[i - 1] + nums[i - 1] % p) % p;
        }
        if(presum[l] == 0)
            return 0;
        var x = presum[l];

        Map<Integer, Integer> map = new HashMap<>();
        // 这是一个什么道理呢,假设数组总和%p = x
        // 我们要找的是(nums[r] - nums[l]) % p = x
        // 移项以后就可以转换为 (nums[r] - x + p) % p = nums[l] % p,加p是为了防止出现负数
        // 然后遍历数组,将所有nums[l] % p 存储在哈希表中
        // 当发现满足上面式子的r存在时,就更新minlen
        int minlen = l;
        for(int i = 0; i <= l; i++){
            map.put(presum[i], i);
            int idx = map.getOrDefault((presum[i] - x + p) % p, -l);
            minlen = Math.min(minlen, i - idx);
        }
        return minlen == l? -1 : minlen;
    }
}
class Solution:
    def minSubarray(self, nums: List[int], p: int) -> int:
        # python中取模运算保证了结果非负
        x = sum(nums) % p
        if x == 0:
            return 0
        l = len(nums)
        minlen = l
        s = 0        # 存储前缀和
        mmap = {s : -1}
        for i in range(l):
            s = (s + nums[i]) % p
            mmap[s] = i
            left = mmap.get((s - x) % p, -l)
            minlen = min(minlen, i - left)
        return minlen if minlen != l else -1

2383. 赢得比赛需要的最少训练时长

2023.3.13 每日一题

题目描述

你正在参加一场比赛,给你两个 正 整数 initialEnergy 和 initialExperience 分别表示你的初始精力和初始经验。

另给你两个下标从 0 开始的整数数组 energy 和 experience,长度均为 n 。

你将会 依次 对上 n 个对手。第 i 个对手的精力和经验分别用 energy[i] 和 experience[i] 表示。当你对上对手时,需要在经验和精力上都 严格 超过对手才能击败他们,然后在可能的情况下继续对上下一个对手。

击败第 i 个对手会使你的经验 增加 experience[i],但会将你的精力 减少 energy[i] 。

在开始比赛前,你可以训练几个小时。每训练一个小时,你可以选择将增加经验增加 1 或者 将精力增加 1 。

返回击败全部 n 个对手需要训练的 最少 小时数目。

示例 1:

输入:initialEnergy = 5, initialExperience = 3, energy = [1,4,3,2], experience = [2,6,3,1]
输出:8
解释:在 6 小时训练后,你可以将精力提高到 11 ,并且再训练 2 个小时将经验提高到 5 。
按以下顺序与对手比赛:
- 你的精力与经验都超过第 0 个对手,所以获胜。
  精力变为:11 - 1 = 10 ,经验变为:5 + 2 = 7 。
- 你的精力与经验都超过第 1 个对手,所以获胜。
  精力变为:10 - 4 = 6 ,经验变为:7 + 6 = 13 。
- 你的精力与经验都超过第 2 个对手,所以获胜。
  精力变为:6 - 3 = 3 ,经验变为:13 + 3 = 16 。
- 你的精力与经验都超过第 3 个对手,所以获胜。
  精力变为:3 - 2 = 1 ,经验变为:16 + 1 = 17 。
在比赛前进行了 8 小时训练,所以返回 8 。
可以证明不存在更小的答案。

示例 2:

输入:initialEnergy = 2, initialExperience = 4, energy = [1], experience = [3]
输出:0
解释:你不需要额外的精力和经验就可以赢得比赛,所以返回 0 。

提示:

n == energy.length == experience.length
1 <= n <= 100
1 <= initialEnergy, initialExperience, energy[i], experience[i] <= 100

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-hours-of-training-to-win-a-competition
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

class Solution:
    def minNumberOfHours(self, initialEnergy: int, initialExperience: int, energy: List[int], experience: List[int]) -> int:
        tmp = sum(energy) + 1 - initialEnergy
        res1 = tmp if tmp > 0 else 0
        mmax = 0
        sumx = 0
        for i, x in enumerate(experience):
            mmax = max(mmax, x + 1 - sumx - initialExperience)
            sumx += x
        return res1 + mmax

1605. 给定行和列的和求可行矩阵

2023.3.14 每日一题

题目描述

给你两个非负整数数组 rowSum 和 colSum ,其中 rowSum[i] 是二维矩阵中第 i 行元素的和, colSum[j] 是第 j 列元素的和。换言之你不知道矩阵里的每个元素,但是你知道每一行和每一列的和。

请找到大小为 rowSum.length x colSum.length 的任意 非负整数 矩阵,且该矩阵满足 rowSum 和 colSum 的要求。

请你返回任意一个满足题目要求的二维矩阵,题目保证存在 至少一个 可行矩阵。

示例 1:

输入:rowSum = [3,8], colSum = [4,7]
输出:[[3,0],
[1,7]]
解释:
第 0 行:3 + 0 = 3 == rowSum[0]
第 1 行:1 + 7 = 8 == rowSum[1]
第 0 列:3 + 1 = 4 == colSum[0]
第 1 列:0 + 7 = 7 == colSum[1]
行和列的和都满足题目要求,且所有矩阵元素都是非负的。
另一个可行的矩阵为:[[1,2],
[3,5]]

示例 2:

输入:rowSum = [5,7,10], colSum = [8,6,8]
输出:[[0,5,0],
[6,1,0],
[2,0,8]]

示例 3:

输入:rowSum = [14,9], colSum = [6,9,8]
输出:[[0,9,5],
[6,0,3]]

示例 4:

输入:rowSum = [1,0], colSum = [1]
输出:[[1],
[0]]

示例 5:

输入:rowSum = [0], colSum = [0]
输出:[[0]]

提示:

1 <= rowSum.length, colSum.length <= 500
0 <= rowSum[i], colSum[i] <= 10^8
sum(rowSum) == sum(colSum)

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-valid-matrix-given-row-and-column-sums
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

没想出来贪心,想到解方程组去了哈哈哈

class Solution:
    def restoreMatrix(self, rowSum: List[int], colSum: List[int]) -> List[List[int]]:
        # 相当于解方程组啊,但是怎么做呢,好像只能一个个试着写

        m = len(rowSum)
        n = len(colSum)
        matrix = [[0] * n for _ in range(m)]
        # print(matrix)
        # 题目思路是这样的,对于每一个格子,取当前格子能取到的最大值
        # 那么遍历这个矩阵,可以构造出每一行都是满足条件的
        # 最后会有一个满足条件的菊展
        # 确实挺难想的
        
        for i in range(m):
            for j in range(n):
                if rowSum[i] >= colSum[j]:
                    x = colSum[j]
                    matrix[i][j] = x
                    rowSum[i] -= x
                    colSum[j] -= x
                else:
                    x = rowSum[i]
                    matrix[i][j] = x
                    rowSum[i] -= x
                    colSum[j] -= x
        return matrix

但是写这个代码还是出了几个问题
首先创建二维数组,我写的是[[0] * n] * m,创建出来确实是m*n的矩阵,但是修改就会出问题
对某一行修改,会复制给其他行
在这里插入图片描述

下面这种形式没有问题
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值