java 分享巧克力_[leetcode 双周赛 11] 1231 分享巧克力_Vicey Wang的博客-程序员秘密

技术标签: java 分享巧克力  

1231 Divide Chocolate 分享巧克力

问题描述

你有一大块巧克力,它由一些甜度不完全相同的小块组成。我们用数组 sweetness 来表示每一小块的甜度。

你打算和 K 名朋友一起分享这块巧克力,所以你需要将切割 K 次才能得到 K+1 块,每一块都由一些 **连续 **的小块组成。

为了表现出你的慷慨,你将会吃掉 总甜度最小 的一块,并将其余几块分给你的朋友们。

请找出一个最佳的切割策略,使得你所分得的巧克力 总甜度最大,并返回这个 最大总甜度。

示例 1:

输入: sweetness = [1,2,3,4,5,6,7,8,9], K = 5

输出: 6

解释: 你可以把巧克力分成 [1,2,3], [4,5], [6], [7], [8], [9]。

示例 2:

输入: sweetness = [5,6,7,8,9,1,2,3,4], K = 8

输出: 1

解释: 只有一种办法可以把巧克力分成 9 块。

示例 3:

输入: sweetness = [1,2,2,1,2,2,1,2,2], K = 2

输出: 5

解释: 你可以把巧克力分成 [1,2,2], [1,2,2], [1,2,2]。

提示:

0 <= K < sweetness.length <= 10^4

1 <= sweetness[i] <= 10^5

思路

读题

将数组分成K+1份, 每份独立且包含是一连续子序列

计算每份元素之和, 使得最小那份是在所有可能分割方案中最大

贪心

假设必定有一最佳答案ans, 它的情况是:

0 < ans <= sum(sweetness)/(K+1)

每个分块之和必定 >= ans

以ans为界限分割的块数量 >= (K+1)

先设ans=avg(sweetness, K+1), 期望最完美的情况下, 大家分到的一样多, 最少的肯定也是所有方案中最多的

如果以此做界限切割不到K+1块, 则缩减期望ans--

每次都假设当前期望ans是最佳切割方案的答案, 不断-1逼近正确答案

贪心切割

每次累加之和大于等于阈值, 就认为这是最佳划分, 作为1块

最终判断是否能切割到(K+1)块

贪心+二分

最佳答案ans还有一个特性:

ans 是最佳答案

ans+1 不是答案

ans-1 是答案

即以ans为界限, 大于它的都无法做出预期切割方案, 小于等于它的都可以做出切割方案, 其中等于它就是最佳切割方案

这样就有一个二分的特性

我们可以在一个确定有正确答案的范围内, 使用二分搜索, 不断调整范围区间, 直至找到正确答案

其中判断正确答案的位置时:

[left, right] mid = (left + right) >> 1

checkout(mid)

可以通过 left = mid+1 向右逼近最佳

不可以通过 right = mid-1 向左逼近最佳

checkout 就是之前的贪心切割

代码实现

贪心

/**

* 超出时间限制 avg调整过慢

*/

class Solution {

public int maximizeSweetness(int[] sweetness, int K) {

// sum 该数组总和

int sum = 0;

for (int swt : sweetness) {

sum += swt;

}

// avg 如果平均分给K+1个人

int avg = sum / (K + 1);

while (avg > 0) {

// cur 当前分块个数

// curSum 每个分块的大小

int cur = 0, curSum = 0;

for (int swt : sweetness) {

curSum += swt;

System.out.printf("cut:%d K:%d curSum:%d avg:%d\n", cur, K, curSum, avg);

if (curSum >= avg) {

System.out.println();

// 从第0块开始切 (cur++ > K or ++cur > (K+1))

if (cur++ >= K) {

return avg;

}

curSum = 0;

}

}

// 以步长为1的"速度"向最佳答案靠近

avg--;

}

return avg;

}

}

贪心+二分

class Solution {

public int maximizeSweetness(int[] sweetness, int K) {

// ans 返回答案

// left 二分左值

// right 二分右值 大小为1e4*1e5

int ans = 0, left = 0, right = (int) 1e9 + 50;

// 最佳甜度必定在[left, right]区间内

while (left <= right) {

int mid = (left + right) >> 1;

// 检测: 以mid为界限, 大于它的都不可以, 小于等于则可以

if (check(sweetness, K + 1, mid)) {

// 最佳mid值在后半段 [mid+1, right]

left = mid + 1;

ans = Math.max(mid, ans);

} else {

// 最佳mid值在前半段 [left, mid-1]

right = mid - 1;

}

}

return ans;

}

private boolean check(int[] arr, int len, int threshold) {

// cur 在分块总和满足阈值threshold的情况下 可切块数量 --> k+1

// sum 单分块之和

int cur = 0, sum = 0;

for (int a : arr) {

sum += a;

// 该连续块之和符合阈值 予以分块

if (sum >= threshold) {

cur++;

sum = 0;

}

}

// 如果在阈值threshold下 可以分成k+1块 该切割策略符合题意

return cur >= len;

}

}

改进: 缩小二分查找范围

/**

* 同上相同的思路

* 不过使用二叉搜索的方式 并且进行了'剪枝'(最终结果必定不超过平均值, 缩小了二叉搜索范围)

*/

class Solution {

public int maximizeSweetness(int[] sweetness, int K) {

int sum = 0;

for (int swt : sweetness) {

sum += swt;

}

// right 采用平均值

int left = 0, right = sum / (K + 1), ans = 0;

while (left <= right) {

int mid = (left + right) >> 1, cur = 0, curSum = 0;

System.out.printf("[left:%d mid:%d right:%d]\n", left, mid, right);

for (int swt : sweetness) {

curSum += swt;

System.out.printf("[cut:%d K:%d] [curSum:%d mid:%d]\n", cur, K, curSum, mid);

if (curSum >= mid) {

if (cur++ >= K) {

break;

}

curSum = 0;

}

}

if (cur > K) {

ans = Math.max(ans, mid);

left = mid + 1;

} else {

right = mid - 1;

}

}

return ans;

}

}

input:

[1,2,3,4,5,6,7,8,9]

5

output:

[left:0 mid:3 right:7]

[cut:0 K:5] [curSum:1 mid:3]

[cut:0 K:5] [curSum:3 mid:3]

[cut:1 K:5] [curSum:3 mid:3]

[cut:2 K:5] [curSum:4 mid:3]

[cut:3 K:5] [curSum:5 mid:3]

[cut:4 K:5] [curSum:6 mid:3]

[cut:5 K:5] [curSum:7 mid:3]

[left:4 mid:5 right:7]

[cut:0 K:5] [curSum:1 mid:5]

[cut:0 K:5] [curSum:3 mid:5]

[cut:0 K:5] [curSum:6 mid:5]

[cut:1 K:5] [curSum:4 mid:5]

[cut:1 K:5] [curSum:9 mid:5]

[cut:2 K:5] [curSum:6 mid:5]

[cut:3 K:5] [curSum:7 mid:5]

[cut:4 K:5] [curSum:8 mid:5]

[cut:5 K:5] [curSum:9 mid:5]

[left:6 mid:6 right:7]

[cut:0 K:5] [curSum:1 mid:6]

[cut:0 K:5] [curSum:3 mid:6]

[cut:0 K:5] [curSum:6 mid:6]

[cut:1 K:5] [curSum:4 mid:6]

[cut:1 K:5] [curSum:9 mid:6]

[cut:2 K:5] [curSum:6 mid:6]

[cut:3 K:5] [curSum:7 mid:6]

[cut:4 K:5] [curSum:8 mid:6]

[cut:5 K:5] [curSum:9 mid:6]

[left:7 mid:7 right:7]

[cut:0 K:5] [curSum:1 mid:7]

[cut:0 K:5] [curSum:3 mid:7]

[cut:0 K:5] [curSum:6 mid:7]

[cut:0 K:5] [curSum:10 mid:7]

[cut:1 K:5] [curSum:5 mid:7]

[cut:1 K:5] [curSum:11 mid:7]

[cut:2 K:5] [curSum:7 mid:7]

[cut:3 K:5] [curSum:8 mid:7]

[cut:4 K:5] [curSum:9 mid:7]

参考资源

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_35510737/article/details/114561372

智能推荐

世界坐标系、相机坐标系、图像坐标系、像素坐标系-程序员秘密

四个坐标系都是什么?图像处理、立体视觉等等方向常常涉及到四个坐标系:世界坐标系、相机坐标系、图像坐标系、像素坐标系 构建世界坐标系只是为了更好的描述相机的位置在哪里,在双目视觉中一般将世界坐标系原点定在左相机或者右相机或者二者X轴方向的中点。接下来的重点,就是关于这几个坐标系的转换。也就是说,一个现实中的物体是如何在图像中成像的。四个坐标系之间的相互转换1. 从世界坐标系到相机坐标系 其中[ x ′ , y ′ ] 为...

在Linux下制作Linux&windows启动盘_「已注销」的博客-程序员秘密

在Linux下制作Linux&amp;windows启动盘如何在Linux-mint环境下,制作其他Linux发行版的UEFI启动盘,以及Windows10的UEFI模式启动盘。对于U盘的操作,可以使用命令行的方式,比如sudo fdisk /dev/sdc这样的命令,对于U盘进行设置;为了直观,也可以使用Gparted这个工具,Ubuntu已自带,其他Debian系安装方式:su...

clion在调试时在代码处自动显示变量值_clion十六进制显示变量_sunashe的博客-程序员秘密

clion在调试时自动显示变量的值不知道动了哪里,导致调试时无法在相应的代码位置显示变量的值,如下红框处没有显示任何信息,之前默认会显示参数的值。可以通过左下角的设置按钮,勾选show values inline,就会显示了,效果如下...

NoSQL数据库介绍(6)_nosql数据库表长度_damipingzi的博客-程序员秘密

6 面向列的数据库     在本章中将研究第三类NoSQL数据存储:面向列的数据库。以列来替代行存储和处理数据的方法起源于分析和商业智能,在一个无共享的大规模并行处理(注:MPP)架构中的列存储可用于构建高性能应用。这一领域引人注目的产品是Sybase IQ和Vertica([ Nor09 ])。然而,在这一章中,面向列的存储类型被视为少一些纯粹性,也包括了整合面向列和行的数据存储

python pdf ocr识别_python – 如何使用OCR有效地从PDF文件目录中提取文本?_weixin_39605191的博客-程序员秘密

在你的代码中,你正在提取文本,但是你不会做任何事情.尝试这样的东西:def extract_txt(file_path):text = textract.process(file_path, method='tesseract')outfn = file_path[:-4] + '.txt' # assuming filenames end with '.pdf'with open(outfn,...

随便推点

复习知识点:UITableView和UICollectionView的常用属性_weixin_30563319的博客-程序员秘密

UITableViewUICollectionView //UICollectionViewLayout //UICollectionViewLayout决定了UICollectionView如何显示在界面上,Apple提供了一个最简单的默认layout对象:UICollectionViewFlowLayout。 //Flow Layout是一个Cells...

hdu 1521_chengouxuan的博客-程序员秘密

排列组合Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 811    Accepted Submission(s): 325Problem Description有n种物品,并且知道每种物品的数量。要求从中选

angular学习(五)—— Scopes_angular2指令中的scope_吴冬冬的博客-程序员秘密

转载请写明来源地址:http://blog.csdn.net/lastsweetop/article/details/51833370Scopes简介Scopes是一个指向application模型的对象,是表达式执行的上下文,模拟application的DOM结构构成自己的层次结构。Scope可以观察表达式和传播事件。Scopes特点Scopes提供了API $watch观察model的变化。

java中cookie的操作(通过cookie实现简单的单点登录)_苍羽的博客-程序员秘密

(一)取得cookie中的相关信息Cookie[] cookies = request.getCookies(); String username = ""; String password = ""; if (cookies != null) { for (int i = 0; i < c

10.24程序员节,喜得一套「MySQL性能优化金字塔法则」_Java架构师联盟的博客-程序员秘密

明天就是10.24程序员节了,这么重大的节日怎么能少得了我来凑热闹呢!这不,最近都在研究MySQL性能优化,偶得朋友相赠一套[MySQL性能优化金字塔法则],简直就是深得我心呐~于是乎,就成就了咱今天的主题,1024程序员节,小编这就来送你一套[MySQL性能优化金字塔法则],毕竟“好好学习,天天向上”“今天不学习,明天变垃圾呀”...主题一:MySQL性能优化金字塔法则这一套学习法则一共分为3篇:基础篇、案例篇、工具篇注:整套法则虽分为3篇,但总共却有51章节(792页)的内容,篇.

css中div不能被撑开高度不能自适应的问题_以下哪个div高度不会被撑开_jianghejie123的博客-程序员秘密

有时我们发现有些div总是不能根据内容自适应,父级元素高度只有一点点,但子元素很高,看起来就像裤子短了很长一截,检查半天也没有结果。面对着这种丑陋的情况,我们真的不知道该如何处理。冷静下来,为什么会出现这种情况,难道是因为使用了浮动的原因吗?确实是浮动能产生很好的效果,但是很多人忽略了浮动的细微性质,那就是浮动使一个块级元素与该层的其他元素游离开来,他漂浮在父元素的上面,父元素无法在视

推荐文章

热门文章

相关标签