LC 410. 分割数组的最大值

这篇具有很好参考价值的文章主要介绍了LC 410. 分割数组的最大值。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

410. 分割数组的最大值

难度: 困难

题目大意:

给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连续子数组。

设计一个算法使得这 k 个子数组各自和的最大值最小。

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 10^6
  • 1 <= k <= min(50, nums.length)

示例 1:

输入:nums = [7,2,5,10,8], k = 2
输出:18
解释:
一共有四种方法将 nums 分割为 2 个子数组。 
其中最好的方式是将其分为 [7,2,5] 和 [10,8] 。
因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。

分析

类似"最大值最小"这样的字眼就可以往二分法上面去思考,那么怎么来进行二分呢,二分的话肯定是要有单调性的,本题是要怎么划分才可以使各自和的最大值最小,那么如果和越大,我们就可以把更多的数放在一组里面,也就是说组越少,同理,如果和越小,我们可以放在同一组里面的数字肯定就更少,也就是说组越多,这样就找单调性,我们可以二分这个值,这个值的区间是多少呢?显然不能小于数组中的最大值,不能大于数组的和,所以我们就确定了上下界,那么思考怎么如果确定了每一组的最大值,怎么求划分的组数呢?我们贪心的做,从前往后枚举,用一个变量累计和,如果和大于当前二分的值,那么就把前面的枚举的数字当成一组,如果组数小于k,那么说明当前二分的值小了,返回false即可,如果大于等于k,那么说明还是可以往下压缩的,返回true

二分查找 + 贪心

class Solution {
public:
    int splitArray(vector<int>& nums, int k) {
        int n = nums.size();
        function<bool(int)> check = [&](int mid) {
            int sum = 0, res = 1; 
            for (int i = 0; i < nums.size(); i++) {
                if (sum + nums[i] > mid) {
                    res ++;
                    sum = nums[i];
                } 
                else {
                    sum += nums[i];
                }
            }
            return res <= k;
        };

        int l = *max_element(nums.begin(), nums.end());
        int r = accumulate(nums.begin(), nums.end(), 0);
        while (l < r) {
            int mid = l + r >> 1;
            if (check(mid)) r = mid;
            else l = mid + 1;
        }
        return l;
    }
};

时间复杂度: O ( n l o g ( r − l ) ) O(nlog(r - l)) O(nlog(rl))

分析

状态定义:我们令f[i][j]表示将前i个数中分成j组,每组和的最大值的最小值

那么状态怎么转移呢?以最后一个不同点为分界点,也就是说,最后一组的起始点,我们可以枚举一下最后一组的起始点,假设当前枚举的是第i个数,要分成j组,最后一组的起始点是u,最后一组的和是sum,那么状态转移方程就是f[i][j] = min(f[i][j], max(f[u - 1][j - 1], sum));状态转移方程出来了,代码就好写了,最初初始化为INFf[0][0] = 0

朴素版 动态规划

class Solution {
public:
    int splitArray(vector<int>& nums, int k) {
        int n = nums.size();
        // 前i个数字中分成j组各自和的最大值的最小值
        vector<vector<int>> f(n + 1, vector<int>(k + 1, 0x3f3f3f3f));
        f[0][0] = 0; 
        for (int i = 1; i <= n; i ++) {
            for (int j = 1; j <= i && j <= k; j ++) {
                int sum = 0;
                for (int u = i; u ; u --) {
                    sum += nums[u - 1];
                    f[i][j] = min(f[i][j], max(f[u - 1][j - 1], sum));
                }
            }
        }
        return f[n][k];
    }
};

时间复杂度: O ( n 2 ∗ k ) O(n^2 * k) O(n2k)

动态规划 + 前缀和

class Solution {
public:
    int splitArray(vector<int>& nums, int k) {
        int n = nums.size();
        vector<vector<int>> f(n + 1, vector<int>(k + 1, 0x3f3f3f3f));
        vector<int> s(n + 1);
        // 前缀和
        for (int i = 1; i <= n; i ++) s[i] = s[i - 1] + nums[i - 1]; 
        
        f[0][0] = 0; 
        for (int i = 1; i <= n; i ++) {
            for (int j = 1; j <= i && j <= k; j ++) {
                for (int u = i; u ; u --) {
                    f[i][j] = min(f[i][j], max(f[u - 1][j - 1], s[i] - s[u - 1]));
                }
            }
        }
        return f[n][k];
    }
};

时间复杂度: O ( n 2 ∗ k ) O(n^2 * k) O(n2k)

和上面的做法没有本质区别,只是加上了一个前缀和,优化一些计算文章来源地址https://www.toymoban.com/news/detail-818279.html

到了这里,关于LC 410. 分割数组的最大值的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【LeetCode: 410. 分割数组的最大值 | 暴力递归=>记忆化搜索=>动态规划 】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域优质创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2024年02月10日
    浏览(42)
  • 算法每日一题: 分割数组的最大值 | 动归 | 分割数组 | 贪心+二分

    Hello,大家好,我是星恒 呜呜呜,今天给大家带来的又是一道经典的动归难题。 题目:leetcode 410 给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k_ 个非空的连续子数组。 设计一个算法使得这 k _个子数组各自和的最大值最小。 示例: 示例 1: 示例 2: 示例

    2024年01月22日
    浏览(47)
  • 想要精通算法和SQL的成长之路 - 分割数组的最大值

    想要精通算法和SQL的成长之路 - 系列导航 原题链接 首先面对这个题目,我们可以捕获几个: 非负整数。 非空连续子数组。 那么我们假设分割后的子数组,和的最大值是 M ,对应分割的子数组个数为 N 。他们之间必然存在以下关系: 分割的子数组个数 N 越多,对应的

    2024年02月07日
    浏览(43)
  • LeetCode 0410.分割数组的最大值:二分

    力扣题目链接:https://leetcode.cn/problems/split-array-largest-sum/ 给定一个非负整数数组 nums 和一个整数  m ,你需要将这个数组分成  m   个非空的连续子数组。 设计一个算法使得这  m   个子数组各自和的最大值最小。   示例 1: 示例 2: 示例 3:   提示: 1 = nums.length = 1000 0 =

    2024年02月20日
    浏览(37)
  • js求数组最大值

    除了使用 Math.max() 方法之外,JavaScript 中还有多种方法可以求数组的最大值,下面介绍其中的几种。 使用循环遍历数组并比较 可以使用 for 循环遍历数组,并使用一个变量来保存数组中的最大值。每当遇到一个比当前最大值大的元素时,更新变量的值。例如: 使用 apply() 方法

    2024年02月16日
    浏览(42)
  • C语言深度剖析,关于查找一个数组里面的最大值(max)、最小值(min)的通俗算法,简单易懂。采用比较法进行查找。

    这里采用了一个假设 假设第一个数为最大值,其他数与第一个数比较。 这个算法与上面求解最大值的方法相反。 1、首先,定义行和列。 用行标记来确定列的数量。 i 来表示行, j来表示列。 2、内嵌的for循环只打印一行所有列。 如,i=3时,此时j=3. 从1*3 遍历到3*3后内嵌循环

    2024年02月08日
    浏览(46)
  • 求二维数组中元素最大值

    题目描述 求二维数组中元素的最大值。 答案 输入 有多组测试数据。 对于每组测试数据,先输入m和n,表示二维数组有m行n列。m或n为0,则结束。(1=m,n=100) 然后输入m*n个整数,即输入各个二维数组元素。 输出 对应输出二维数组的最大值。 样例输入  Copy 样例输出  Copy

    2024年02月11日
    浏览(57)
  • 生成窗口最大值数组【中等难度】

    给定一个整数数组 nums 和一个正整数 k,滑动一个大小为 k 的窗口,从数组的左边到右边,找到每个窗口中的最大值。 示例 1: 输入:nums = {1, 3, -1, -3, 5, 3, 6, 7} 、k = 3 输出:3 3 5 5 6 7 我们可以使用双端队列(deque)来解决这个问题。双端队列可以在两端进行插入和删除操作,

    2024年02月12日
    浏览(47)
  • C语言:二维数组中求最大值

    二维数组中求最大值 思路:  创建一个变量存储数组第一个元素  用for循环以此遍历数组,如果比数组第一个元素大,就把max替换为大的数  输出结果如下  

    2024年02月11日
    浏览(52)
  • js求数组最大值 的8中方法

    8种在JavaScript中求取数组最大值的方法: Math.max()方法: 使用简单,适用于已知数组中没有NaN或Infinity的情况。 优点:代码简洁,性能较好。 缺点:不适用于包含NaN或Infinity的数组,需要使用展开运算符来传递参数。 reduce()方法: 可以处理包含NaN或Infinity的数组。 优点:灵活

    2024年02月10日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包