zoukankan      html  css  js  c++  java
  • 【算法】数组分段和最大值最小问题

    描述

    题目:给定一个数组,和一个值k,数组分成k段。要求这k段子段和最大值最小。求出这个值。

    解析

    (1)暴力搜索

                     n                             n-1
    M[n, k] = min { max { M[j, k-1], ∑ Ai } }
                    j=1                            i=j

    n表示数组长度,k表示数组分成几段。初始化条件:

    M[1, k] = A0
              n-1
    M[n, 1] = ∑ Ai
              i=0

    (2)动态规划

    递归算法拥有指数时间的复杂度,并且会重复计算一些M值。这类的算法一般可以使用动态规划进行优化。使用数组保存一些已经计算得到的值,采用自底向上进行计算

    (3)二分查找

      此题可以想象成把数据按顺序装入桶中,m即是给定的桶数,问桶的容量至少应该为多少才能恰好把这些数装入k个桶中(按顺序装的)。

      首先我们可以知道,桶的容量最少不会小于数组中的最大值,即桶容量的最小值(小于的话,这个数没法装进任何桶中),假设只需要一个桶,那么其容量应该是数组所有元素的和,即桶容量的最大值;其次,桶数量越多,需要的桶的容量就可以越少,即随着桶容量的增加,需要的桶的数量非递增的(二分查找就是利用这点);我们要求的就是在给定的桶数量m的时候,找最小的桶容量就可以把所有的数依次装入k个桶中。在二分查找的过程中,对于当前的桶容量,我们可以计算出需要的最少桶数requiredPainters,如果需要的桶数量大于给定的桶数量k,说明桶容量太小了,只需在后面找对应的最小容量使需要的桶数恰好等于k;如果计算需要的桶数量小于等于k,说明桶容量可能大了(也可能正好是要找的最小桶容量),不管怎样,该桶容量之后的桶容量肯定不用考虑了(肯定大于最小桶容量),这样再次缩小查找的范围,继续循环直到终止,终止时,当前的桶容量既是最小的桶容量。

      对于数组 1 2 3 4 5 6 7,假设k=3,最小桶容量为7(要5个桶),最大桶容量为28(一个桶)

    第一行表示桶容量,第二行表示需要的桶数,即要求桶数量恰为k的最小桶容量

    代码

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <limits.h>
    #include <numeric>
    #include "Solution.h"
    
    using namespace std;
    //===================方案1==========================
    //递归的暴力搜素算法 , 指数时间的复杂度
    int partition(vector<int> nums, int len, int k) {
        if (k == 1)
            return accumulate(nums.begin(), nums.begin()+len, 0);
        if (len == 1)
            return nums[0];
    
        int best = INT_MAX;
        for (int j = 1; j <= len; j++)
            best = min(best, max(partition(nums, j, k-1), accumulate(nums.begin()+j, nums.begin()+len, 0)));
    
        return best;
    }
    
    //==================方案二======================
    //改进的动态规划算法
    //时间复杂度:O(kN2)  空间复杂度:O(kN)
    int DP_findMax(vector<int> nums, int k){
        vector<vector<int>> dp(nums.size()+1,vector<int>(k,0));
        vector<int> sums(nums.size()+1,0);
        for(int i = 1;i<=nums.size();++i){
            sums[i] = sums[i-1] + nums[i];
        }
        for (int i = 1; i <= nums.size(); i++)
            dp[i][1] = sums[i];
        for (int i = 1; i <= k; i++)
            dp[1][i] = nums[0];
        for (int i = 2; i <= k; i++) {
            for (int j = 2; j <= nums.size(); j++) {
                int best = INT_MAX;
                for (int p = 1; p <= j; p++) {
                    best = min(best,max(dp[p][i-1],sums[j] - sums[p]));
                }
                dp[j][i] = best;
            }
        }
        return dp[nums.size()][k];
    }
    
    
    int getRequiredPainters(vector<int> nums, int mid) {
        int total = 0, numPainters = 1;
        for (int i = 0; i < nums.size(); i++) {
            total += nums[i];
            if (total > mid) {
                total = nums[i];
                numPainters++;
            }
        }
        return numPainters;
    }
    
    
    //========================方案三========================
    // 二分查找算法
    //时间复杂度:O(N log ( ∑ Ai )).   空间复杂度:0(1)
    int BinarySearch(vector<int> nums, int k) {
        int max_val = INT_MIN;
        for (int i = 0; i < nums.size(); i++) {
            max_val = max(max_val, nums[i]);
        }
        int lo = max_val; //数组中最大元素
        int hi = accumulate(nums.begin(), nums.end(), 0); //数组求和
    
        while (lo < hi) {  //二分查找
            int mid = (lo + hi)/2;
            int requiredPainters = getRequiredPainters(nums, mid);
            if (requiredPainters <= k)
                hi = mid;
            else
                lo = mid+1;
        }
        return lo;
    }
    
    
    int main() {
    
        int a[] = {5,1,4,2,3};
        vector<int> va(a, a+5);
        int k = 3;
        cout<<partition(va,va.size(),k)<<endl;
        cout<<DP_findMax(va,k)<<endl;
        cout<<BinarySearch(va,k)<<endl;
        return 0;
    }
  • 相关阅读:
    Appium运行时,error: Logcat capture failed: spawn ENOENT的解决办法
    pwntools使用简介3
    pwntools使用简介2
    pwnable.kr memcpy之write up
    pwnable.kr uaf之wp
    【笔记】objdump命令的使用
    pwnable.kr cmd2之write up
    pwnable.kr cmd1之write up
    pwnable.kr lotto之write up
    pwnable.kr blackjack之write up
  • 原文地址:https://www.cnblogs.com/ygh1229/p/10637504.html
Copyright © 2011-2022 走看看