C++前缀和算法的应用:分割数组的最多方案数 原理源码测试用例

news2024/11/16 0:48:52

本文涉及的基础知识点

C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频

题目

给你一个下标从 0 开始且长度为 n 的整数数组 nums 。分割 数组 nums 的方案数定义为符合以下两个条件的 pivot 数目:
1 <= pivot < n
nums[0] + nums[1] + … + nums[pivot - 1] == nums[pivot] + nums[pivot + 1] + … + nums[n - 1]
同时给你一个整数 k 。你可以将 nums 中 一个 元素变为 k 或 不改变 数组。
请你返回在 至多 改变一个元素的前提下,最多 有多少种方法 分割 nums 使得上述两个条件都满足。
示例 1:
输入:nums = [2,-1,2], k = 3
输出:1
解释:一个最优的方案是将 nums[0] 改为 k 。数组变为 [3,-1,2] 。
有一种方法分割数组:

  • pivot = 2 ,我们有分割 [3,-1 | 2]:3 + -1 == 2 。
    示例 2:
    输入:nums = [0,0,0], k = 1
    输出:2
    解释:一个最优的方案是不改动数组。
    有两种方法分割数组:
  • pivot = 1 ,我们有分割 [0 | 0,0]:0 == 0 + 0 。
  • pivot = 2 ,我们有分割 [0,0 | 0]: 0 + 0 == 0 。
    示例 3:
    输入:nums = [22,4,-25,-20,-15,15,-16,7,19,-10,0,-13,-14], k = -33
    输出:4
    解释:一个最优的方案是将 nums[2] 改为 k 。数组变为 [22,4,-33,-20,-15,15,-16,7,19,-10,0,-13,-14] 。
    有四种方法分割数组。
    参数范围
    n == nums.length
    2 <= n <= 105
    -105 <= k, nums[i] <= 105

分析

原理

nums[0,p)-nums[p,m_c) 如果等于0,则符合条件。修改nums[i]

i <p左边增加 k - nums[i]
i>=p右边增加 k - nums[i]

大致流程

先获取初始状态(未修改)所有数的和。
枚举p,左边减右边的放到mModifyRightLeftSubRight中。
初始状态下,mModifyRightLeftSubRight[0]就是分割方案数。
枚举修改nums[i]。

如果i在左边则初始mModifyLeftLeftSubRight[-iSub]就是方案数
如果i在右边则初始mModifyRightLeftSubRight[iSub]就是方案数

变量解释

llTotanums的和
mModifyLeftLeftSubRight;符合i < p,各方案nums[0,p)-nums[p,m_c)
mModifyRightLeftSubRight符合i>=p,各方案nums[0,p)-nums[p,m_c)

时间复杂度

两次循环,时间复杂度都是O(n),故总时间复杂度是O(n)。

代码

核心代码

class Solution {
public:
int waysToPartition(vector& nums, int k) {
m_c = nums.size();
long long llTotal = std::accumulate(nums.begin(), nums.end(), 0LL);
std::unordered_map<long, int> mModifyRightLeftSubRight;
//[0,p)左半部分,[p,m_c)右半部分
long long llR = 0;//llR是nums[p,m_c)的和
for (int p = m_c - 1; p > 0; p–)
{
llR += nums[p];
const long long llLeft = llTotal - llR;
mModifyRightLeftSubRight[llLeft - llR]++;
}
int iRet = mModifyRightLeftSubRight[0];//不改变任何数,能拆分的数量
std::unordered_map<long, int> mModifyLeftLeftSubRight;
//修改nums[p]
llR = 0;
for (int i = m_c - 1; i >= 0; i–)
{
int iSub = (k - nums[i]);
const int cur = mModifyRightLeftSubRight[iSub]+ mModifyLeftLeftSubRight[-iSub];
iRet = max(iRet, cur);
llR += nums[i];
const long long llLeft = llTotal - llR;
mModifyRightLeftSubRight[llLeft - llR]–;
mModifyLeftLeftSubRight[llLeft - llR]++;
}
return iRet;
}
int m_c;
};

测试用例

template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
assert(v1[i] == v2[i]);
}
}

template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}

int main()
{
Solution slu;
vector nums;
int k;
int res;
nums = { 0,0,0 };
k = 1;
res = slu.waysToPartition(nums, k);
Assert(2, res);
nums = { 0,0,0,0 };
k =3;
res = slu.waysToPartition(nums, k);
Assert(3, res);
nums = { -2, -1, 3, 4, 5 };
k = 3;
res = slu.waysToPartition(nums, k);
Assert(0, res);
nums = { -2, -1, 3, 4, 5 };
k = 2;
res = slu.waysToPartition(nums, k);
Assert(0, res);
nums = { -2, -1, 3, 4, 5 };
k = -3;
res = slu.waysToPartition(nums, k);
Assert(0, res);
nums = { -1, -1, 3, 4, 5 };
k = -3;
res = slu.waysToPartition(nums, k);
Assert(1, res);
nums = { -1,3 };
k = 3;
res = slu.waysToPartition(nums, k);
Assert(1, res);
nums = { 5,4,3 };
k = 8;
res = slu.waysToPartition(nums, k);
Assert(0, res);
nums = { 5,4,3 };
k = 1;
res = slu.waysToPartition(nums, k);
Assert(1, res);

nums = { 5,4,3 };
k = 7;
res = slu.waysToPartition(nums, k);
Assert(1, res);
nums = { 3,5,4 };
k = 1;
res = slu.waysToPartition(nums, k);
Assert(1, res);
nums = { 3,5,4 };
k = 1;
res = slu.waysToPartition(nums, k);
Assert(1, res);
nums = { 3,5,4 };
k = 0;
res = slu.waysToPartition(nums, k);
Assert(0, res);

//CConsole::Out(res);

}

2023年4月旧代码

class Solution {
public:
int waysToPartition(vector& nums, int k) {
long long llSum = 0;
std::unordered_map<long long, int> mSumNum;//各前缀和数量
vector vSum;
for (int i = 0; i < nums.size(); i++)
{
llSum += nums[i];
vSum.emplace_back(llSum);
if (i + 1 < nums.size())
{
mSumNum[llSum]++;
}
}
int iRet = 0;
if (0 == llSum % 2)
{
iRet += mSumNum[llSum / 2];
}
const long long llNewSum = llSum + k - nums.back();
if (0 == llNewSum % 2)
{
iRet =max(iRet, mSumNum[llNewSum / 2]);
}
std::unordered_map<long long, int> mRightSumNum;
for (int i = nums.size() - 2; i >= 0; i–)
{
const long long& llCurSum = vSum[i];
mSumNum[llCurSum]–;
mRightSumNum[llCurSum]++;
const long long llNewSum = llSum + k - nums[i];
if (llNewSum & 1)
{//改变后是奇数
continue;
}

		int iCurRet = mSumNum[llNewSum / 2];
		iCurRet += mRightSumNum[llNewSum / 2 - (k - nums[i])];
		iRet = max(iRet, iCurRet);
	}
	return iRet;
}

};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《闻缺陷则喜算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

鄙人想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
墨家名称的来源:有所得以墨记之。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境:

VS2022 C++17

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1133368.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

区块链外包开发需要注意的问题

在进行区块链外包开发时&#xff0c;有一些关键问题需要特别注意&#xff0c;以确保项目的成功和质量。以下是一些需要考虑的问题&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.明确的需求和目标&…

公众号视频怎么下载,3个方法教你如何操作!

公众号视频怎么下载&#xff0c;今天教你如何操作下载公众号视频&#xff0c;废话不多说&#xff0c;看教程 关于分享的教程我们分享一下三种方法 1&#xff1a;公众号视频查看源代码 2&#xff1a;获取公众号小助手下载公众号视频 3&#xff1a;QQ浏览器下载法 公众号视频…

C盘满了怎么清理文件?

电脑的C盘是我们电脑存储系统文件和应用程序的一个重要盘符&#xff0c;很多人经常会遇到C盘空间不足的问题&#xff1b;虽然我们可以通过卸载程序或者删除文件来释放空间&#xff0c;但是在这个过程中往往会误删掉一些重要的文件&#xff0c;造成部分程序可能无法正常使用。 因…

python 连接oracle数据库的过程步骤(亲测有效)--windows

目录 1. 安装 cx_Oracle 模块 2. 安装 oracle 客户端 3. 连接 oracle数据库 连接oracle数据库的过程中遇到很多问题&#xff0c;不过好在一一解决了&#xff0c;特地将解决问题的过程记录下来供友友们参考~ 1. 安装 cx_Oracle 模块 具体可参考 PyCharm 安装 cx_Oracle 失败…

急需一个免费又实用的配音软件~

做自媒体的朋友肯定需要用到大量的文案配音&#xff0c;又不想自己配&#xff0c;就只能在网上找AI配音的小程序、网站和软件&#xff0c;可是找了&#xff0c;又有很多效果不好&#xff0c;情绪单调。 不过没关系&#xff0c;今天我将为大家介绍一款超实用的配音网站&#xf…

【Unity程序技巧】2D音乐中心管理器

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

MII,RMII,GMII,RGMII区别

一、MII,GMII为百兆网口 1.MII ①引脚接线图 ②引脚定义 2.GMII ①引脚接线图 ②引脚定义 二、GMII,RGMII为千兆网口 1.GMII ①GMII引脚接线图 ②GMII引脚定义 2.RGMII ①RGMII引脚接线图 ②RGMII引脚定义 三、PCB走线注意 ① RGMII 模式下&#xff0c;MAC 的 RXD0&a…

WireShark使用入门

背景 Wireshark&#xff0c;又被称为网络封包分析软件&#xff0c;是一种开源且功能十分强大的工具。该工具的主要功能是截取各种网络封包&#xff0c;并尽可能显示出最为详细的网络封包资料。它使用WinPCAP作为接口&#xff0c;直接与网卡进行数据报文交换。 Wireshark支持W…

简单有效的方法压缩图片大小,尝试一键自动压缩!

如果图片过大&#xff0c;会占据我们过多的存储空间&#xff0c;可能会引起电脑的卡顿&#xff0c;传输的速度很慢&#xff0c;也很容易传输失败&#xff0c;这时候可以把图片压缩&#xff08;https://www.yasuotu.com/&#xff09;一下&#xff0c;那么怎么才能快速压缩图片大…

【Note】完全二叉树的类型定义

完全二叉树 完全二叉树&#xff1a;深度为k&#xff0c;结点数为n的二叉树&#xff0c;如果其结点1~n的位置序号分别与等高的满二叉树的结点1~n的位置序列一一对应&#xff0c;则为完全二叉树。 完全二叉树的特点&#xff1a; 叶子结点只可能出现在最后两层。度为1的结点个数…

关于c语言,你必须了解的运行流程

流程图 1.程序的翻译环境和执行环境 在ANSIC任何一种实现下,都存在两种环境,程序的翻译环境和执行环境 翻译环境:将源代码转换成机器指令 执行环境:用于执行代码 2.详解编译链接 简单的说一个代码从编写到看到控制台的结果分为编译链接两步即可,接下来我们将详细解释编译链接中…

6 STM32标准库函数 之 内部集成电路(I2C) 所有函数的介绍及使用

6 STM32标准库函数 之 内部集成电路&#xff08;I2C&#xff09;所有函数的介绍及使用 1. 图片有格式2 文字无格式六 库函数之内部集成电路&#xff08;I2C&#xff09;所有函数的介绍及使用前言一、图片预览&#xff0c;无格式&#xff08;CSDN&#xff09;二、 I2C库函数固件…

(链表) 25. K 个一组翻转链表 ——【Leetcode每日一题】

❓ 25. K 个一组翻转链表 难度&#xff1a;困难 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保…

Python-股票市场用于算法交易的人类反馈强化学习 (RLHF)

ChatGPT 的成功使人类反馈强化学习 (RLHF) 技术成为人们关注的焦点。RLHF 是一种机器学习方法,它结合了强化学习 (RL) 和人类反馈 (HF) 来改进学习过程。这篇文章将使您对 RLHF 有一个全面的了解。它描述了 RLHF 在算法交易(algo transactions)中的应用,并提供了可执行的 P…

TLSF内存管理算法原理详解

TLSF算法原理概述 TLSF算法的核心优势在于其通过位运算执行内存块匹配算法&#xff0c;并兼顾了内存管理的额外内存消耗&#xff0c;无论是从内存池申请内存块还是释放内存块回内存池其操作都是O(1)。TLSF组织了一张一二级索引表映射其所有管理内存块的闲忙状态&#xff0c;并通…

简单聊下Redis的主从复制和哨兵机制以及集群(面试题)

ChatGPT的简答&#xff1a; Redis的主从复制&#xff08;Master-Slave Replication&#xff09;是指将一个Redis服务器的数据复制到其他Redis服务器的过程&#xff0c;其中一个服务器作为主节点&#xff08;Master&#xff09;&#xff0c;而其他服务器作为从节点&#xff08;S…

基于SSM的居家养老系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

快速学习如何注册域名企业邮箱,只需5分钟

网站最重要的一个东西&#xff0c;就是你要有一个域名邮箱&#xff0c;显得你的邮箱更加专业&#xff0c;怎么样去申请一个域名邮箱&#xff0c;之前也出过一些内容给过大家&#xff0c;很多方法已经过时了&#xff0c;今天给大家更新一个最新版的&#xff0c;怎么样去申请一个…

【C++代码】安排行程,N皇后,解数独--代码随想录

题目&#xff1a;重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;所以该行程必…

6、实现多段运动【51单片机控制步进电机-TB6600系列】

摘要&#xff1a;本节介绍用控制步进电机三个主要参数角度、速度、方向&#xff0c;实现简单的步进电机多段控制 一、目标功能 输入多个目标角度&#xff0c;以及每个角度对应的速度&#xff0c;实现步进电机的多段多速度转动 二、计算过程 2.1 简化C与n函数关系 根据上一节内…