【LeetCode】1703. 得到连续 K 个 1 的最少相邻交换次数

news2024/11/24 13:46:28

题目描述

给你一个整数数组 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)

方法一:滑动窗口,前缀和,步步优化

思路:

  • 我们需要移动数组中的 1 ,使得出现连续 k 个 1 ,且移动的次数尽可能少。直接求最优解很困难,因此通过适当的暴力枚举来得到答案。
    直觉上最容易想到:选择 「相邻」(忽略 0 )的 k 个 1 ,把它们移到一块。这就给 「滑动窗口」这个算法提供了条件,上述所提到的枚举,就是 枚举滑动窗口
  1. 总体思路
  • 找出所有满足条件的窗口,条件是 **窗口内正好有 k 个 1 ,且窗口两个端点都是 1 ** ;
  • 对于每个窗口, 求出把其中 k 个 1 移到一块的最小 cost , 并更新全局最优解 minCost 。
    在这里插入图片描述
  1. 给定一个窗口,如何求解「 该窗口的最优解 」?
    在这里插入图片描述
  • 以上图中的第一个窗口为例:
  • 把所有 1 移到一起,其实就是把 0 往窗口两端移动 。对于每个 0 ,只有左移和右移两种选择。
    在这里插入图片描述
  • 对于每个 0 ,我们都能得到它的 cost ,那么整个窗口的 cost ,就是这些 0 的 cost 之和。
    在这里插入图片描述
  1. 算法优化
    上述方法的时间复杂度很高,因此需要进行优化。
    ———
    3.1 合并连续的 0
  • 对于连续的 0 ,它们的 cost 都是一样的,因此我们可以把加法变成乘法,也就是说,「把连续的 0 ,看作一个整体 0 , 整体0 的 cost 等于其中每个 0 的 cost 再乘以 0 的个数
  • 需要注意的是,如果两个 1 之间没有 0, 我们就记为零个 0 , 它的 cost 就是假设中间有 0 时,那些 0 的 cost 。在这里插入图片描述
  • 合并 0 之间, 得到一个新数组。
  • 这一步的时间复杂度 需要 O(n) ,扫描一遍 nums 就得到。在这里插入图片描述
    ————
    3.2 在 zeros 数组上,计算第一个窗口的解
  • 有了 zeros 数组后,我们来算第一个窗口的解。在 zeros 上, 窗口的长度为 k-1 , 窗口的端点为 [0, k-2] 。
  • 对于窗口中每个位置的 cost ,就像是一座山峰,两端是 1 , 往中间逐个递增。这里第一个窗口的 cost 是 [1, 2, 2, 1] 。把每个位置的 cost 乘上这个位置 0 的个数,就是 zeros[i] , 再求和就得到窗口整体的 cost 。
  • 这一步的时间复杂度 是O(k)。在这里插入图片描述————
    3.3 窗口开始滑动
  • 有了 zeros 数组后, 滑动窗口变得简单。在 nums 上,窗口的长度是变化的,而在zeros 上, 窗口的长度则是固定的
  • 第一个窗口的解需要花费O(k)的时间,如果之后每个窗口也都需要花费O(k),那整体的时间复杂度就需要乘以平方了。
  • 因此,要利用滑动窗口的特性 , 「下一个窗口的解,可以由前一个窗口的解快速得到」,如果能在O(1)的时间解决, 那整体就是线性复杂度了。
  • Q:如何通过上一个窗口的解求得下一个窗口的解呢?
    • 根据窗口长度的奇偶性,分情况讨论,如果窗口长度是偶数
    • 假设当前窗口从 i 到 j ,那么上一个窗口就是从 i-1 到 j-1 。我们可以找到一个中点 mid ,它左边的 cost 都减少 1 , 右边的 cost 都增加 1 。 因为减少或增加的 1 需要与 zeros 中的值相乘, 所以 cost 的变化可以通过求 zeros 上 「区间和」来快速得到。
      • 通过区间端点(i, j)算出中点坐标 mid;
      • 求出窗口中点左边,即[i-1, mid-1] 范围的区间和;
      • 求出窗口右边,即[mid+1, j] 范围的区间和;
      • 更新 cost。

//窗口长度k-1是偶数的情况
int mid = (i + j) / 2;
cost -= GetRangeSum(i-1, mid-1);
cost += GetRangeSum(mid+1, j);
在这里插入图片描述

  • 如果窗口长度是奇数
  • 只是分割区间的位置稍有不同,大体上还是一致的。
    //窗口长度k-1是奇数的情况
    int mid = (i + j) / 2;
    cost -= GetRangeSum(i-1, mid-1);
    cons += GetRangeSum(mid, j)在这里插入图片描述
  • 从代码的简洁性考虑,可以合并奇、偶两种情况,窗口长度是 k-1 ,如果 k-1 是偶数,即 k 是奇数,则右边区间的起点 + 1:
    //合并上述两种情况
    int mid = (i + j) / 2;
    cost -= GetRangeSum(i-1, mid-1);
    cons += GetRangeSum(mid+k%2, j)
  • 如果 GetRangeSum() 的时间复杂度为O(1),那么更新窗口的时间复杂度也就是O(1),窗口从头滑到尾,整体就是线性复杂度O(n)。
    ——————
    3.4 数组的区间和
  • 最后一个目标,就是实现常数复杂度的 GetRangeSum() 。通过预先处理,构造出 「前缀和」 数组后,就可以在O(1)时间内得到区间和。

情况

  • 通过;

收获

  • 这道题用到的知识点太多了,也很难,今天可能花了2个小时,甚至不止,在这道题上,并且不算特别明白。有空需要多看看。

时间复杂度:O(n)
空间复杂度:O(n)
在这里插入图片描述

class Solution {
private:
    vector<int> zeros;
    vector<int> pre {0}; 

    void GenerateZeros(const vector<int> &nums){
        int n = nums.size(), i = 0;
        while(i < n && nums[i] == 0) i++ ;
        while(i < n){
            int j = i + 1;
            while(j < n && nums[j] == 0) j ++;
            if(j < n) zeros.push_back(j - i -1);
            i = j;
        }
    }
    void GeneratePresum(vector<int>& zeros){
        for(int i=0; i<zeros.size(); i++){
            pre.push_back(pre.back() + zeros[i]); 
        }
    }
    int GetRangeSum(int left, int right){
        return pre[right+1] - pre[left];
    }
public:
    int minMoves(vector<int>& nums, int k) {
        // 计算数组 zeros
        GenerateZeros(nums);

        int cost = 0;
        int left = 0, right = k - 2;
        for(int i=left; i<=right; i++){
            cost += zeros[i] * (min(i+1, right-i+1));
        }

        int minCost = cost;

        GeneratePresum(zeros);
        int i=1, j = i + k - 2;
        for(; j<zeros.size(); i++, j++){
            int mid=(i + j) / 2;
            cost -= GetRangeSum(i-1, mid-1);
            cost += GetRangeSum(mid+k%2, j);
            minCost = min(minCost, cost);
        }
        return minCost;
    }
};

参考题解:

  1. 【多图】新手教程,一步步带你写,把Hard分解成Easy

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

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

相关文章

入门:镜像结构介绍

前面我们了解了Docker的相关基本操作&#xff0c;实际上容器的基石就是镜像&#xff0c;有了镜像才能创建对应的容器实例&#xff0c;那么我们就先从镜像的基本结构开始说起&#xff0c;我们来看看镜像到底是个什么样的存在。 我们在打包项目时&#xff0c;实际上往往需要一个基…

C++PrimerPlus 第八章 函数探幽-8.1 C++内联函数

目录 8.1 C内联函数 8.1 C内联函数 内联函数是C为提高程序运行速度所做的一项改进。常规函数和内联函数之间的主要区别不在于编写方式&#xff0c;而在于C编译器如何将它们组合到程序中。要了解内联函数与常规函数之间的区别&#xff0c;必须深入到程序内部。 编译过程的最终…

微机原理与接口技术笔记

文章目录前言储存系统与技术材料高速储存器缓冲储存器&#xff08;Cache&#xff09;材料&#xff0c;局部性&#xff0c;访问方式Cache全相联映射Cache交换与一致性单核CPU一致性处理多核CPU的MESI协议主储存器&#xff08;内存&#xff09;主要技术指标容量带宽内存模组与内存…

牛客题霸sql入门篇之条件查询(四)之高级查询

牛客题霸sql入门篇之条件查询(四)之高级查询 4 计算函数 4.1 查询GPA最高值 4.1.1 题目内容 4.1.2 示例代码 SELECT gpa FROM user_profile WHERE university复旦大学 ORDER BY gpa desc limit 1; -- LIMIT 初始位置&#xff0c;记录数 一个参数就是记录数4.1.3 运行结果 4…

Python Flask构建微信小程序订餐系统 (四)

🔥 创建微信小程序 🔥 微信开发者工具下载 并完成安装 在PyCharm 工具里面 order目录下面 创建mina 文件夹 通过微信小程序开发工具创建微信小程序工程 获取微信小程序ID

数据挖掘Java——PageRank算法的实现

一、PageRank算法的前置知识 PageRank算法&#xff1a;计算每一个网页的PageRank值&#xff0c;然后根据这个值的大小对网页的重要性进行排序。 从用户角度来看&#xff0c;一个网站就是若干页面组成的集合。然而&#xff0c;对于网站的设计者来说&#xff0c;这些页面是经过…

嵌入式系统开发笔记109:多个LED的闪烁控制

文章目录前言一、一般思路1、LED0 100ms闪烁&#xff0c;LED1 200ms闪烁2、LED0 100ms闪烁&#xff0c;LED1 300ms闪烁3、LED0 200ms闪烁&#xff0c;LED1 600ms闪烁二、通过循环变量实现1、LED0 500ms闪烁&#xff0c;LED1 700ms闪烁2、LED0 15ms闪烁&#xff0c;LED1 7ms闪烁…

Java——LRUCache

概念 简单来说&#xff0c;由于我们的空间是有限的&#xff0c;所以发明了这个数据结构&#xff0c;当我们的空间不够添加新的元素时&#xff0c;就会删除最近最少使用的元素。 其底层逻辑通过哈希表和链表共同实现。哈希表中存储链表的每一个元素&#xff0c;方便进行元素的…

Mysql分布式锁(三)悲观锁实现并发

在前面的方法中&#xff0c;一条sql语句中仍然存在着很多问题&#xff0c;于是我们可以用悲观锁来代替解决。 假设我们不用一条sql&#xff0c;仍然用先查询&#xff0c;判断&#xff0c;最后更新来实现业务。 文章目录悲观锁 select...for update1. 不加悲观锁1) 两个机器连接…

因果推断2--深度模型介绍(个人笔记)

目录 一、方法介绍 1.1TarNet 1.1.1TarNet 1.1.2网络结构 1.1.3counterfactual loss 1.1.4代码实现 1.2Dragonet 1.3DRNet 1.4VCNet VCNET AND FUNCTIONAL TARGETED REGULARIZATION FOR LEARNING CAUSAL EFFECTS OF CONTINUOUS TREATMENTS 二、待补充 一、方法介绍 …

AcWing 第82场周赛

AcWing 第82场周赛 竞赛 - AcWing B 4783. 多米诺骨牌 - AcWing题库 模拟题&#xff0c;考察代码描述问题的能力。 由题意所给的数学形式化定义中看出&#xff0c;所给的骨牌初始序列 L 和 R 的顺序一定是相互交错的&#xff0c;即 ...LRLRLRLR... 所以&#xff0c;一旦遇到…

KNN算法 搜索最优超参数:n_neighbors/weights/p

目录 一&#xff1a;遍历参数 超参调优测试 二&#xff1a;网格模型 超参调优测试 三&#xff1a;模型保存 四&#xff1a;模型使用 一&#xff1a;遍历参数 超参调优测试 1.1 超参调试&#xff0c;找到模型最优解[仅做测试&#xff0c;得出最优&#xff1a;n_neighbors, …

PowerDesigner导入SQL脚本生成带中文注释(comment)的ER图并保存为图片格式(含通用可执行vb脚本文件)

目录 1、安装数据库建模工具PowerDesigner 16.5 2、打开 PowerDesigner&#xff0c;选择反向工程 3、选择数据库类型 4、导入SQL脚本文件并生成数据库表模型 5、去掉Diagram画板黑色网格线&#xff08;选做&#xff09; 6、ER图常规显示&#xff08;包含是否为Null及表名…

D. Same Count One(模拟 + 思维转换(行不行,从列入手))

Problem - D - Codeforces ChthollyNotaSeniorious收到了AquaMoon的一份特殊礼物&#xff1a;n个长度为m的二进制数组。AquaMoon告诉他&#xff0c;在一次操作中&#xff0c;他可以选择任何两个数组和1到m中的任何位置&#xff0c;并交换这些数组中位置的元素。 他对这个游戏很…

RabbitMQ知识总结一

更多知识在我的语雀平台&#xff1a; https://www.yuque.com/ambition-bcpii/muziteng RabbitMQ 1. RabbitMQ引言 1.1 什么是MQ MQ&#xff08;Message Queue&#xff09;消息队列&#xff0c;是基础数据结构中“先进先出”的一种数据结构。一般用来解决应用解耦&#xff0…

带token的登陆页面爆破方法(burp宏+爬虫脚本分享)

文章目录前言一、token参数分析二、burp设置宏操作三、爬虫脚本四、小结前言 在工作中&#xff0c;会遇到很多登陆页面有token保护&#xff0c;如果用Burpsuite直接抓取数据包并使用爆破模块&#xff0c;则会因token过期导致无法爆破。此时至少可以采用三种办法&#xff1a; 第…

Java诊断工具——arthas,实时监控,了解一下

文章目录1、arthas 简介官方文档2、arthas 的使用场景3、安装&启动3.1 安装3.2 启动4、常用命令5、使用示例5.1 stack5.2 jad5.3 sc5.4 watch5.5 trace5.6 jobs5.7 logger5.8 dashboard5.9 redefine6、其它1、arthas 简介 arthas是由阿里巴巴中间件团队开源的Java诊断工具。…

kubernetes对外服务之Ingress

目录 ​​​​​​​一、Ingress 是什么 1.1Service的作用 1.2Ingress简介 二、Ingress 安装 三、Ingress 代理访问 3.1Ingress HTTP 代理访问 3.2 Ingress: HTTPS 代理访问 3.3Ingress Contronler怎么工作的&#xff1f; ​​​​​​​​​​​​​​一、Ingress 是什…

Java核心实操:内存溢出 实战、内存泄漏实战

文章很长&#xff0c;而且持续更新&#xff0c;建议收藏起来&#xff0c;慢慢读&#xff01;疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 &#xff1a; 免费赠送 :《尼恩Java面试宝典》 持续更新 史上最全 面试必备 2000页 面试必备 大厂必备 涨薪必备 免费赠送 经典…

ARM系列之MMU TLB和ASID基础概念介绍。

目录1、为什么要设计TLB&#xff1f;TLB中不包含我们需要的映射关系怎么办&#xff1f;2、TLB中都包含了啥&#xff1f;3、那什么是ASIDAddress Space ID&#xff08;ASID&#xff09;4、小结内存寻址简要过程如下&#xff1a;VA以页表大小取余&#xff0c;得到PA的低位&#x…