leetcode
leetcode 2401 ~ 2450
使数组和小于等于 x 的最少时间

使数组和小于等于 x 的最少时间

难度:

标签:

题目描述

You are given two 0-indexed integer arrays nums1 and nums2 of equal length. Every second, for all indices 0 <= i < nums1.length, value of nums1[i] is incremented by nums2[i]. After this is done, you can do the following operation:

  • Choose an index 0 <= i < nums1.length and make nums1[i] = 0.

You are also given an integer x.

Return the minimum time in which you can make the sum of all elements of nums1 to be less than or equal to x, or -1 if this is not possible.

 

Example 1:

Input: nums1 = [1,2,3], nums2 = [1,2,3], x = 4
Output: 3
Explanation: 
For the 1st second, we apply the operation on i = 0. Therefore nums1 = [0,2+2,3+3] = [0,4,6]. 
For the 2nd second, we apply the operation on i = 1. Therefore nums1 = [0+1,0,6+3] = [1,0,9]. 
For the 3rd second, we apply the operation on i = 2. Therefore nums1 = [1+1,0+2,0] = [2,2,0]. 
Now sum of nums1 = 4. It can be shown that these operations are optimal, so we return 3.

Example 2:

Input: nums1 = [1,2,3], nums2 = [3,3,3], x = 4
Output: -1
Explanation: It can be shown that the sum of nums1 will always be greater than x, no matter which operations are performed.

 

Constraints:

  • 1 <= nums1.length <= 103
  • 1 <= nums1[i] <= 103
  • 0 <= nums2[i] <= 103
  • nums1.length == nums2.length
  • 0 <= x <= 106

代码结果

运行时间: 220 ms, 内存: 16.3 MB


/* 
思路:
1. 使用Java Stream的方式来实现。
2. 在每一秒钟后,使用stream更新 nums1 的值。
3. 通过stream计算和来检查是否 <= x。
*/

import java.util.stream.IntStream;

public class Solution {
    public int minTime(int[] nums1, int[] nums2, int x) {
        int n = nums1.length;
        int[] sum = new int[n + 1];
        for (int t = 0; t < n; t++) {
            for (int i = 0; i < n; i++) {
                nums1[i] += nums2[i];
            }
            int total = IntStream.of(nums1).sum();
            if (total <= x) {
                return t + 1;
            }
        }
        return -1;
    }
}

解释

方法:

题解使用了动态规划的策略,首先预先判断nums1的初始和是否已经小于等于x,若是,则直接返回0秒。接着,考虑最多需要length次操作,对nums2进行降序排序,并计算出一个阈值thres。thres代表通过对所有元素设置为0后可以减少的最大可能值,若x小于该阈值,则直接返回-1表示无法实现。然后使用动态规划数组dp,其中dp[j]存储前i个元素操作j次能达到的最大减少值。遍历所有组合,并根据每次操作的累积结果和x的关系来判断所需的最小时间。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
在题解中提到的阈值`thres`是如何计算的?能否详细解释其意义及计算过程?
在题解中,`thres`的计算是通过排序后的`nums2`数组来实现的,计算公式为`sum(i * b for i, b in enumerate(sorted_nums2))`,这里的`i`是元素的索引,`b`是`nums2`中降序排序后的元素。此公式的本质是考虑每个元素`b`通过最大化其减少值的潜力来估计可以通过操作减少的最大总和。索引`i`代表如果操作到该元素,则它是第`i+1`个被操作的,因此它的贡献被加倍。`thres`的意义在于,它代表了在最理想的情况下(即每次操作都能达到最大单次减少量),通过操作`nums2`可以减少的最大可能总和。
🦆
为什么在判断`x`小于`thres`时可以直接返回`-1`?这种情况代表了什么实际的意义?
如果`x`小于`thres`,这意味着即使在最理想的情况下(即每次操作都能达到最大单次减少量),通过操作`nums2`也无法达到使数组和小于等于`x`的目标。因此,如果`x`小于`thres`,则表示无论如何操作,都无法满足条件,因此直接返回`-1`表示这一不可能性。
🦆
动态规划数组`dp`中的`dp[j]`代表什么意义?在动态规划过程中,它是如何被更新的?
`dp[j]`在动态规划数组中存储的是前`i`个元素操作`j`次能达到的最大减少值。在动态规划过程中,对于每个元素组合`(nu2, nu1)`,代码会反向遍历`j`从`i`到`1`,利用状态转移方程`dp[j] = max(dp[j], dp[j-1] + nu2 * j + nu1)`来更新`dp[j]`。这里`dp[j-1] + nu2 * j + nu1`考虑了如果在当前步骤将该元素设置为0,那么通过这次操作新增的减少值是多少。
🦆
在代码中,为什么需要对`nums2`和`nums1`的元组按降序排序?这样的排序有什么特殊目的或优势?
对`nums2`和`nums1`的元组按降序排序的目的是为了优先处理那些具有更大潜在减少值的元素。通过这种方式,可以更快地减少总和,尽可能地在较少的操作次数内达到目标值`x`。降序排序确保了在动态规划处理过程中,每次都尝试通过最大化每个操作的影响来达到目标,这是一个策略性的决策,以提高算法的效率和可能性成功减少到目标值。

相关问题