2024.1.19力扣每日一题——使数组和小于等于 x 的最少时间

题目来源

力扣每日一题;题序:2809

我的题解

题解参考官方题解

方法一 动态规划

若能找到一个最小的时间t使得数组和小于等于x,则最多在一轮遍历(n秒)中找到,否则就找不到。所以观察重置为零的数,会按照 nums2的速度增长,所以对于所有操作的数,我们应该优先操作增长速度慢的数。
如果我们选择多个索引 i 1 , i 2 , … , i k i_1,i_2,…,i_k i1,i2,,ik,那么按照 n u m s 2 [ i 1 ] ≤ n u m s 2 [ i 2 ] ≤ … ≤ n u m s 2 [ i k ] nums_2[i_1]≤nums_2[i_2]≤…≤nums_2[i_k] nums2[i1]nums2[i2]nums2[ik]的顺序进行设置是最优的。按照 nums2 的大小对所有数值对进行排序(非递减顺序)。用 dp[j][i] 表示如果对前 j个元素进行 i次操作,可以减少的最大总值,初始值为零。对于第 j 个元素,我们可以选择对其进行操作或者不操作,由此可以得到状态转移方程:
dp[j][i]=max⁡(dp[j−1][i],dp[j−1][i−1]+ n u m s 2 nums_2 nums2[j−1]×i+ n u m s 1 nums_1 nums1[j−1])
其中有 1≤i≤j≤n。
最后返回最小的 t,使满足 sum( n u m s 1 nums_1 nums1)+sum( n u m s 2 nums_2 nums2)×t−dp[n][t]≤x,如果不存在返回 −1。

时间复杂度:O( n 2 n^2 n2)
空间复杂度:O( n 2 n^2 n2)。动态规划数组空间

public int minimumTime(List<Integer> nums1, List<Integer> nums2, int x) {
   
    int n = nums1.size(), s1 = 0, s2 = 0;
    int[][] dp = new int[n + 1][n + 1];
    //这里是技巧:如何不改变原数组对其进行排序
    Integer index[]=new Integer[nums2.size()];
    for(int i=0;i< nums2.size();i++){
   
        index[i]=i;
    }
    Arrays.sort(index,(a,b)->nums2.get(a)-nums2.get(b));
    for (int i = 0; i < n; i++) {
   

        int a = nums1.get(i), b = nums2.get(i);
        s1 += a;
        s2 += b;
    }
    for (int j = 1; j <= n; ++j) {
   
        int in=index[j-1];
        int b = nums2.get(in), a = nums1.get(in);
        for (int i = j; i > 0; --i) {
   
            dp[j][i] = Math.max(dp[j - 1][i], dp[j - 1][i - 1] + i * b + a);
        }
    }
    for (int i = 0; i <= n; i++) {
   
        if (s2 * i + s1 - dp[n][i] <= x) {
   
            return i;
        }
    }
    return -1;
}
方法二 动态规划(空间优化)

dp[i] 的状态只和 dp[i−1]有关。
所以可以省去第一个维度,从而优化空间,从 O( n 2 n^2 n2) 优化到 O(n),其中 n 是输入数组的长度。

时间复杂度:O( n 2 n^2 n2)
空间复杂度:O(n)

public int minimumTime(List<Integer> nums1, List<Integer> nums2, int x) {
   
 	int n = nums1.size(), s1 = 0, s2 = 0;
    int[] dp = new int[n + 1];
    Integer index[]=new Integer[nums2.size()];
    for(int i=0;i< nums2.size();i++){
   
        index[i]=i;
    }
    Arrays.sort(index,(a,b)->nums2.get(a)-nums2.get(b));
    for (int i = 0; i < n; i++) {
   

        int a = nums1.get(i), b = nums2.get(i);
        s1 += a;
        s2 += b;
    }
    for (int j = 1; j <= n; ++j) {
   
        int in=index[j-1];
        int b = nums2.get(in), a = nums1.get(in);
        for (int i = j; i > 0; --i) {
   
            dp[i] = Math.max(dp[i], dp[i - 1] + i * b + a);
        }
    }
    for (int i = 0; i <= n; i++) {
   
        if (s2 * i + s1 - dp[i] <= x) {
   
            return i;
        }
    }
    return -1;
}

注意技巧:如何在不改变原数组的情况下对数组进行排序,需要额外的序号数组

有任何问题,欢迎评论区交流,欢迎评论区提供其它解题思路(代码),也可以点个赞支持一下作者哈😄~

最近更新

  1. TCP协议是安全的吗?

    2024-01-22 23:14:09       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-22 23:14:09       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-22 23:14:09       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-22 23:14:09       20 阅读

热门阅读

  1. Leetcode 3012. Minimize Length of Array Using Operations

    2024-01-22 23:14:09       36 阅读
  2. PG DBA培训23:PostgreSQL执行计划与统计信息

    2024-01-22 23:14:09       33 阅读
  3. 前端开发领域的细分领域与特点

    2024-01-22 23:14:09       33 阅读
  4. 转 义 字 符

    2024-01-22 23:14:09       31 阅读
  5. Vue与React:核心异同点解析

    2024-01-22 23:14:09       28 阅读
  6. LeetCode 每日一题 Day 46 ||枚举

    2024-01-22 23:14:09       35 阅读
  7. k8s-pvc/pv扩容记录

    2024-01-22 23:14:09       29 阅读
  8. 电话号码的字母组合-算法

    2024-01-22 23:14:09       32 阅读
  9. 一个简单的Vue实例

    2024-01-22 23:14:09       37 阅读
  10. 深度学习-自然语言推断

    2024-01-22 23:14:09       33 阅读
  11. 详细分析对比copliot和ChatGPT的差异

    2024-01-22 23:14:09       92 阅读