Leetcode1712. 将数组分成三个子数组的方案数[C++题解]:双指针和前缀和
文章目录
- 本题分析
- 题目链接
本题分析
题目重述: 给定一个非负的数组,要求将其分成3个非空的三段,要求每一段的数字之和依次递增(可以相等),求总共有几种分法。
题目解答:
双指针算法
思路:枚举第二个分界点,看第一个分界点有多少种选择 。
数组下标从1开始,即从1到n: a[1] ,a[2],…a[n], 第二个分界点下标是i,第一个分界点下标是x,这里下标属于后一段。这样把数组分成三段(用下标来表示):[1~x-1], [x ~i-1],[ i ~ n]. 三段之和分别记为A,B,C。
对于分界点i,我们看第一个分界点x的取值范围,假设其可取的最小下标为j,可取的最大下标为k,那么对于第二个分界点i,满足题意的方案数就有:k-j+1 种。
比如样例,
输入:nums = [1,2,2,2,5,0]
输出:3
解释:nums 总共有 3 种好的分割方案:
[1] [2] [2,2,5,0]
[1] [2,2] [2,5,0]
[1,2] [2,2] [5,0]
下标从1开始 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
数组内容 | 1 | 2 | 2 | 2 | 5 | 0 |
假设第二个分界点下标i=4,则C=7,第一个分界点x可取多少呢? (j,k)=(3,3),故此时的方案数: 3-3+1=1种。
假设第二个分界点 i=5,则C=5,那么第一个分界点x可取多少呢? (j,k)=(3,4),故此时的方案数: 4-3+1=2种。
总的方案数就是1+2=3种。
下面的问题就是这个 j和k 怎么求?
j的含义是:i给定之后, 第一个分界点最靠前可以取到什么位置。
i需要满足什么呢?
j越往左走,那么中间B就会越大,为了满足B≤C,那么必然j有下界。
在第二个分界点往后走的时候,C在变小,为了满足B≤C,j也应该往后走。也就是说,j会随着i向右移而单调向右移。
k的含义是:i给定之后,第二个分界点最靠后可以取到什么位置。
k需要满足什么呢?
k需要满足a[k]~a[i-1]的和≥ a[1] ~a[k-1]的和,即B≥A。
k往右走,在i固定时,B会变小,A会变大,为了满足B≥A,必然存在一个最大的k,越过了这个边界,就不再满足B≥A。
根据上面 j的推理,可以利用反证法证明, k会随着i向右移而单调向右移。
总之:最小取值j由右边(C≥B)限制, 最大取值 k由左边(A≤B)限制。
当然还有小技巧:可以使用前缀和来求出一段的和:通过O(1)的时间求出一段的和。
注意:下面对代码进行解释
对于边界(j,k)的判断思路不太一样
while(s[n]-s[i-1] < s[i-1]-s[j-1]) j++;
while( k+1<i && s[k] <= s[i-1]-s[k]) k++;
下面进行解释:
对于 左边界j:左边界被右边限制,只要B大于C,j就一直j++,直到第一个满足B小于等于C。这就是满足题意的第一个分界点的最小取值,即左边界。
对于右边界k:右边界k被左边限制,我们要试探性地往右走:对于下标是k+1的第一个分界点,是否满足 A小于等于B,如果满足,就继续k++。当然,第一个下标永远小于第二个下标i,尝试k+1时也要满足k+1<i.
ac代码
class Solution {public:int waysToSplit(vector<int>& nums) {int n = nums.size(),mod = 1e9 +7;vector<int> s(n+1); //前缀和数组for(int i=1;i<=n;i++) s[i] =s[i-1]+nums[i-1]; //下标往后移动了一个,从1开始int res=0;//枚举第二个分界点i,记住下标从1开始for( int i=3, j=2, k=2; i<= n; i++){//判断(j,k)的位置//对于左边界j:如果B>C,j一直往右移动,直到B≤Cwhile(s[n]-s[i-1] < s[i-1]-s[j-1]) j++;//对于右边界k: 如果A一直小于等于B,k就一直往右移//本身是A小于等于B 即[1,k-1] ≤ [k,i-1]//试探一下,看k取k+1是否成立,如果成立就k++。//现在要试探k+1 即 [1,k] ≤ [k+1, i-1]while( k+1<i && s[k] <= s[i-1]-s[k]) k++;if(j<=k && s[k-1] <= s[i-1]-s[k-1] && s[n]-s[i-1] >= s[i-1]-s[j-1] )res=( res+ k-j+1) %mod;}return res;}
};
题目链接
Leetcode1712. 将数组分成三个子数组的方案数
Leetcode1712. 将数组分成三个子数组的方案数[C++题解]:双指针和前缀和相关推荐
- LeetCode 1712. 将数组分成三个子数组的方案数(前缀和 + 二分查找)
文章目录 1. 题目 2. 解题 221 / 3117,前7.1% 574 / 9692,前 5.9% 周赛前2题如下: LeetCode 5641. 卡车上的最大单元数(排序,模拟) LeetCod ...
- 【动态规划】将一个包含m个整数的数组分成n个数组,每个数组的和尽量接近,及其变形(Python实现)
背景 实际的问题来源于LQA系统的人员分配工作量,有两种方式,一种是 平均分配,一种是按给定比例分配.不需要AC,能得到符合题意的解就算达成目标. 平均分配 一个order订单包含一个xls表格,内含 ...
- LeetCode 2035. 将数组分成两个数组并最小化数组和的差
文章目录 一.题目 1.题目描述 2.基础框架 3.原题链接 二.解题报告 1.思路分析 2.算法详解 3.时间复杂度 4.代码详解 三.本题小知识 四.加群须知 一.题目 1.题目描述 给你一个 ...
- 网易实习生算法组编程题二:求数组的两个子数组和的最大值
求一个正整数数组的两个子数组,使其和相等,找出满足这样要求的子数组和的最大值,若不存在,则返回-1.比如[1,1,2,3,5,20],结果为6. #include<iostream> #i ...
- LeetCode 2035. 将数组分成两个数组并最小化数组和的差(状态压缩DP)
文章目录 1. 题目 2. 解题 1. 题目 给你一个长度为 2 * n 的整数数组. 你需要将 nums 分成 两个 长度为 n 的数组,分别求出两个数组的和,并 最小化 两个数组和之 差的绝对值 ...
- 一个子数组最大值的问题
题目要求: 1.输入一个整形数组,数组里有正数也有负数. 2.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 3.求所有子数组的和的最大值.要求时间复杂度为O(n) 发表一 ...
- php 把一个数组分成有n个元素的二维数组的算法
一.第一种解法 <?php //把一个数组分成几个数组//$arr 是数组//$num 是数组的个数function partition($arr,$num){//数组的个数$listcount ...
- 寻找数组中只出现一次的数
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是O(n),空间复杂度是O(1). 分析:首先考虑这个问题的一个简单版本:一个数组里除了 ...
- 结对开发--求二维数组的最大子数组
小组成员:信1201-1班 黄亚萍 信1201-1班 袁亚姣 一.题目要求 程序要使用的数组放在一个叫 input.txt 的文件中, 文件格式是: 数组的行数, 数组的列数, 每一行的元素, ...
最新文章
- LeNet5,AlexNet,MobileNet它们的前身你知道吗?
- Kali渗透测试——UPNP网关发现工具Miranda
- origin画图_把heatmap翻一转:imshow的origin和extent
- 大剑无锋之你了解HTTPS吗?那么它为什么安全?【面试推荐】
- 英语笔记:写作:Free admissionsto museums
- python logger_牛逼!python中的logging模块居然这么好用!
- 网络拓扑结构与静态特征
- 把RDD简单的转换成DataFrames
- 一块神奇的树莓派电子板竟让我学会了Linux系统
- angular遇到问题
- 关于代理服务器的原理及用法
- 【原创】STM32低功耗模式及中断唤醒(基于BMI160及RTC)的研究
- 用纯fme批量生成界址点成果表(模板格式全部自拟)
- AWT:实现简单的java计算器
- 左神算法学习日记——二叉树遍历(二)
- 并发控制五(封锁的粒度)
- linux运行docker容器,添加映射端口
- 已解决requests.exceptions.ConnectTimeout: HTTPConnectionPool(host=‘123.96.1.95‘, port=30090): Max retri
- 《The C Programming Language》答案(第一章)
- 案例-站狼云品智美站助力必信空调中国制造领先品牌
热门文章
- 如何用CMD开启3389与查看3389端口
- 即时通讯 TCP UDP
- JavaScript要点 (二) 使用误区
- Reveal:分析iOS UI该武器
- 【Android Developers Training】 104. 接受地点更新
- 2013年3月空调类品牌网络知名度排名
- 如何捕获window.print点击打印或取消_原来1:1的CAD图纸要这样打印!学了这么久才知道...
- 在形态的世界里寻找基数的影子
- 谷歌身份验证器验证码不对怎么回事_地面最强下载器:IDM+【安卓】详细介绍...
- java各种包的用途