C++前缀和算法的应用:得到连续 K 个 1 的最少相邻交换次数 原理源码测试用例
本文涉及的基础知识点
C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频
滑动窗口
题目
给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1 。每一次移动,你可以选择 相邻 两个数字并将它们交换。
请你返回使 nums 中包含 k 个 连续 1 的 最少 交换次数。
示例 1:
输入:nums = [1,0,0,1,0,1], k = 2
输出:1
解释:在第一次操作时,nums 可以变成 [1,0,0,0,1,1] 得到连续两个 1 。
示例 2:
输入:nums = [1,0,0,0,0,0,1,1], k = 3
输出:5
解释:通过 5 次操作,最左边的 1 可以移到右边直到 nums 变为 [0,0,0,0,0,1,1,1] 。
示例 3:
输入:nums = [1,1,0,1], k = 2
输出:0
解释:nums 已经有连续 2 个 1 了。
提示:
1 <= nums.length <= 105
nums[i] 要么是 0 ,要么是 1 。
1 <= k <= sum(nums)
分析
假定
nums[left]和nums[r]都是1,且nums[left,r]共有k个1。
左移(右移)的顺序不影响结果
换种思考方式,将0移出。假定left < m0 < m1 < r。先移m0,移动m1,需要m0-left,移动m1,需要m1-(left+1),共需要m0+m1-left2-1。先移m1,移动m0,需要m1-left,移动m0,需要m0-(left+1),共需要m0+m1-left2-1。
公式:如果有n个数左移,则交换次数为:这些数距离left的和-n*(n-1)/2。
如果m1左移更划算,那么m0左移也更划算
m0相比与m1,左移消耗更少,右移消耗更多。显然左移更划算。右移类似。
代码解释
vOneIndex | 依次记录了nums[i]等于1的索引。m是[left,r]中第一个右移划算的0。 |
---|---|
[left,m)中的0 左移,[m,end)中的0右移。由于nums[end]是1,所以[m,end]中的0,就是[m,end)中的0。 | |
v0Dis[m] - v0Dis[left] | [left,m)中的0 全部移到索引0处需要的交换次数。 |
left * iLeft0Num | [left,m)中的0 全部从left移动0的交换次数。 |
两种相减就是 [left,m)中的0 全部 移动到left,处需要的交换次数。 | |
r * iRight0Num | 是[m,r)中的0全部从r移动到0。 |
v0Dis[r] - v0Dis[m ] | [m,r)中的0全部移动到0。 |
两者相减 | 就是[m,r)的0全部移到r需要的次数。 |
时间复杂度
O(n)。枚举i,时间复杂度O(n);枚举m,时间复杂度O(n)。注意m不是从头开始,所以枚举m的总时间复杂度是O(n),而不是每个i都是O(n)。
代码
核心代码
class Solution {
public:
int minMoves(vector& nums, int k) {
m_c = nums.size();
vector vOneIndex;
for (int i = 0; i < m_c ; i++)
{
if (1 == nums[i])
{
vOneIndex.emplace_back(i);
}
}
vector v0Dis = { 0 };//记录nums[0,i)中,nums[i]等于0时 i之和,也就是将所有nums[i]移到0处
for (int i = 0; i < m_c; i++)
{
long long llAdd = (0 == nums[i]) ? i : 0;
v0Dis.emplace_back(llAdd+v0Dis.back());
}
vector v0Num = { 0 };//记录nums[0,i)中0的个数
for (const auto& n : nums)
{
v0Num.emplace_back(v0Num.back() + (0==n));
}
long long llRet = INT_MAX;
int m = 0;
for (int i = 0; i + k - 1 < vOneIndex.size(); i++)
{
const int left = vOneIndex[i];
const int r = vOneIndex[i + k - 1];
if (m < left)
{
m = left + 1;
}
for (; m < r; m++)
{
if (1 == nums[m])
{
continue;
}
//[left,m)中的0 左移
const int iLeft0Num = v0Num[m] - v0Num[left];
//[m,end)中的0右移,由于nums[end]是1,所以[m,end]中的0,就是[m,end)中的0
const int iRight0Num = v0Num[r] - v0Num[m];
const int iLeftCur = m - left - iLeft0Num;
const int iRightCur = r - m - (iRight0Num - 1);
if (iRightCur <= iLeftCur)
{
break;
}
}
//m 等于r,也符合下面的逻辑[left,r)和[r,r),右移为空
const long long iLeft0Num = v0Num[m] - v0Num[left];
const long long iRight0Num = v0Num[r] - v0Num[m];
const long long llLeftMove = v0Dis[m] - v0Dis[left] - left * iLeft0Num - (iLeft0Num - 1) * iLeft0Num / 2;
const long long llRightMove = r * iRight0Num - (v0Dis[r] - v0Dis[m]) - (iRight0Num - 1) * iRight0Num / 2;
llRet = min(llRet, llLeftMove + llRightMove);
}
return llRet;
}
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()
{
vector nums = { 1, 0, 0, 1, 0, 1 };
int k = 2;
auto res = Solution().minMoves(nums,k);
Assert(1, res);
nums = { 1, 0, 0, 0, 0, 0, 1, 1 };
k = 3;
res = Solution().minMoves(nums, k);
Assert(5, res);
nums = { 1,1,0,1 };
k = 2;
res = Solution().minMoves(nums, k);
Assert(0, res);
//CConsole::Out(res);
}
扩展阅读
视频课程
有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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
相关文章:

C++前缀和算法的应用:得到连续 K 个 1 的最少相邻交换次数 原理源码测试用例
本文涉及的基础知识点 C算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 滑动窗口 题目 给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1 。每一次移动,你可以选择 相邻 两个数字并将它们交换。 请你返回使 nums 中包…...
目标检测YOLO实战应用案例100讲-基于YOLOv5的航拍图像旋转目标检测
目录 前言 国内外研究历史与现状 目标检测技术的研究历史与现状...

H5前端开发——BOM
H5前端开发——BOM BOM(Browser Object Model)是指浏览器对象模型,它提供了一组对象和方法,用于与浏览器窗口进行交互。 通过 BOM 对象,开发人员可以操作浏览器窗口的行为和状态,实现与用户的交互和数据传…...

stable diffusion如何解决gradio外链无法开启的问题
问题确认 为了确认gradio开启不了是gradio库的问题还是stable diffusion的问题,可以先执行这样一段demo代码 import gradio as grdef greet(name):return "Hello " name "!"demo gr.Interface(fngreet, inputs"text", outputs&q…...
SpringMvc-面试用
一、SpringMvc常用注解 1、修饰在类的 RestController RequestMapping("/test")RestController是什么?其实是一个复合注解 Controller //其实就是Component ResponseBody //独立的注解 public interface RestController {}RequestMapping 也可以认…...
并发编程 # 3
文章目录 一、进程和线程的比较二、GIL全局解释器锁1.引入2.Python解释器的种类结论:在CPython解释其中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势。得出结论:GIL锁就是保证在同一时刻只…...

ESP32C3 LuatOS TM1650①驱动测试
合宙TM1650驱动资料 TM1650.lua源码 引脚连接 TM1650ESP32C3SCLGPIO5SDAGPIO4 下载TM1650.lua源码,并以文件形式保存在项目文件夹中 驱动测试源码 --注意:因使用了sys.wait()所有api需要在协程中使用 -- 用法实例 PROJECT "ESP32C3_TM1650" VERSION …...

TCP为什么需要三次握手和四次挥手?
一、三次握手 三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包 主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备 过程如下ÿ…...

【C++】一些C++11特性
C特性 1. 列表初始化1.1 {}初始化1.2 initializer_list 2. 声明2.1 auto2.2 typeid2.3 decltype2.4 nullptr 3. STL3.1 新容器3.2 新接口 4. 右值引用5. 移动构造与移动赋值6. lambda表达式7. 可变参数模板8. 包装器9. bind 1. 列表初始化 1.1 {}初始化 C11支持所有内置类型和…...
leetcode 647. 回文子串、516. 最长回文子序列
647. 回文子串 给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成&#…...
Vue Router 刷新当前页面
Vue项目, 在实际工作中, 有些时候需要在 加载完某些数据之后对当前页面进行刷新, 以期 onMounted 等生命周期函数, 或者 数据重新加载. 总之是期望页面可以重新加载一次. 目前总结有三种途径可实现以上需求: 一, reload 直接刷新页面 window.location.reload(); $router.go(…...
lstm 回归实战、 分类demo
预备知识 lstm 参数 输入、输出格式 nn.LSTM(input_dim,hidden_dim,num_layers); imput_dim 特征数 input:(样本数、seq, features_num) h0,c0 (num_layers,seq, hidden_num) output: (样本数、seq, hidden_dim) 再加一个全连接层,将 outpu…...

实践DDD模拟电商系统总结
目录 一、事件风暴 二、系统用例 三、领域上下文 四、架构设计 (一)六边形架构 (二)系统分层 五、系统实现 (一)项目结构 (二)提交订单功能实现 (三࿰…...

`SQL`编写判断是否为工作日函数编写
SQL编写判断是否为工作日函数编写 最近的自己在写一些功能,遇到了对于工作日的判断,我就看了看sql,来吧!~(最近就是好疲惫) 我们一起看看(针对ORACLE) 1.声明: CREATE OR REPLACE PACKAGE GZYW_2109_1214.PKG_FUN_GETDAY_HDAY AS /** * 通过节假日代码获取指定的日期[查找基…...

零信任身份管理平台,构建下一代网络安全体系
随着数字化时代的到来,网络安全已成为企业和组织面临的一项重要挑战。传统的网络安全方法已经无法满足不断演变的威胁和技术环境。近期,中国信息通信研究院(简称“中国信通院”)发布了《零信任发展研究报告( 2023 年&a…...

《数据结构、算法与应用C++语言描述》使用C++语言实现链表队列
《数据结构、算法与应用C语言描述》使用C语言实现链表队列 定义 队列的定义 队列(queue)是一个线性表,其插入和删除操作分别在表的不同端进行。插入元素的那一端称为队尾(back或rear),删除元素的那一端称…...

RT-Thread学习笔记(四):RT-Thread Studio工具使用
RT-Thread Studio工具使用 官网详细资料实用操作1. 查看 RT-Thread RTOS API 文档2.打开已创建的工程3.添加头文件路径4. 如何设置生成hex文件5.新建工程 官网详细资料 RT-Thread Studio 用户手册 实用操作 1. 查看 RT-Thread RTOS API 文档 2.打开已创建的工程 如果打开项目…...

【计算机网络笔记】OSI参考模型中端-端层(传输层、会话层、表示层、应用层)功能介绍
系列文章目录 什么是计算机网络? 什么是网络协议? 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能(1)——速率、带宽、延迟 计算机网络性能(2)…...
RabbitMQ高级知识点
以下是一些 RabbitMQ 的高级知识点: 1. Exchange: RabbitMQ 中的 Exchange 是消息路由器,用来接收消息并且转发到对应的 Queue 中。Exchange 有四种类型:Direct Exchange、Fanout Exchange、Topic Exchange 和 Headers Exchange。…...
Node直接执行ts文件
Node直接执行ts文件 1、常规流程 node 执行 【ts 文件】 流程: 1、编写ts代码 2、编译成js代码 [命令如 :tsc xx.ts] 3、执行js代码 [node xx.js]2、直接执行 想要直接执行 ts 文件,需要安装如下依赖工具。 执行如下命令: # 安装…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...

STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...