2938. 区分黑球与白球

news2024/10/4 18:03:31

题目

桌子上有 n 个球,每个球的颜色不是黑色,就是白色。

给你一个长度为 n 、下标从 0 开始的二进制字符串 s,其中 10 分别代表黑色和白色的球。

在每一步中,你可以选择两个相邻的球并交换它们。

返回「将所有黑色球都移到右侧,所有白色球都移到左侧所需的 最小步数」。

示例 1:

输入s = "101"

输出1

解释:我们可以按以下方式将所有黑色球移到右侧:

  • 交换 s[0]s[1]s = "011"
    最开始,1 没有都在右侧,需要至少 1 步将其移到右侧。

示例 2:

输入s = "100"

输出2

解释:我们可以按以下方式将所有黑色球移到右侧:

  • 交换 s[0]s[1]s = "010"
  • 交换 s[1]s[2]s = "001"
    可以证明所需的最小步数为 2

示例 3:

输入s = "0111"

输出0

解释:所有黑色球都已经在右侧。

提示:

  • 1 <= n == s.length <= 10^5
  • s[i] 不是 '0',就是 '1'

代码

完整代码

#include <string.h>
#include <stdio.h>
long long minimumSteps(char* s) {
    int n = strlen(s);
    long long res = 0;
    long long cntof1 = 0;
    for (int i = 0; i < n; i++)
    {
        if(s[i] == '1')
        {
            cntof1 ++;
        }
        else
        {
            res += cntof1;
        }
    }
    return res;
}

思路分析

该代码的目的是计算将所有黑色球(‘1’)移到右侧,所有白色球(‘0’)移到左侧所需的最小步数。算法核心类型是贪心算法,通过遍历字符串 s,每当遇到一个白色球(‘0’),计算将其左侧的所有黑色球(‘1’)移到其右侧所需的步数,并累加这些步数,从而得到最小步数。

拆解分析

  1. 变量初始化

    int n = strlen(s);
    long long res = 0;
    long long cntof1 = 0;
    
    • n:存储字符串 s 的长度。
    • res:存储最终结果,即最小步数。
    • cntof1:用于统计遍历过程中遇到的黑色球(‘1’)的数量。
  2. 遍历字符串

    for (int i = 0; i < n; i++)
    {
        if (s[i] == '1')
        {
            cntof1++;
        }
        else
        {
            res += cntof1;
        }
    }
    
    • 遍历字符串 s 的每个字符:
      • 如果字符是 ‘1’(黑色球),cntof1 递增。
      • 如果字符是 ‘0’(白色球),res 增加当前 cntof1 的值。这意味着将当前白色球左侧的所有黑色球向右移动到该白色球的右侧所需的步数。
  3. 返回结果

    return res;
    
    • 返回总步数 res

复杂度分析

  • 时间复杂度

    • 遍历字符串 s 需要 O(n) 的时间,其中 n 是字符串的长度。
    • 在遍历过程中,只有简单的加法和判断操作,因此整体时间复杂度为 O(n)
  • 空间复杂度

    • 使用了几个额外的变量(nrescntof1),空间复杂度为 O(1)

综上所述,代码的时间复杂度为 O(n),空间复杂度为 O(1)

结果

结果

一题多解

分析最优性

当前算法的核心思路是贪心策略:每遇到一个白色球,统计其左侧黑色球的数量,并将这些黑色球移动到右侧。这种方法直接反映了问题的本质:我们只需要计算每个白色球左侧所有黑色球的位置差异,并累加这些差异即可。

更详细的贪心思路分析
  1. 遍历字符一次
    • 每个字符只需要访问一次,所以时间复杂度是 O(n)
  2. 累加步数
    • 计算步数时,只需一个累加操作,空间复杂度是 O(1)

为什么是最优的

  1. 时间复杂度

    • 对于一个长度为 n 的字符串,只需要遍历一遍,所以时间复杂度是 O(n)。没有办法在更短的时间内解决这个问题,因为至少需要访问每个字符一次。
  2. 空间复杂度

    • 只使用了常量级别的额外空间,即用于计数的几个变量。因此,空间复杂度是 O(1),没有多余的存储需求。

其他可能的思路

虽然当前方法已经最优,但为了完整性,这里列出其他一些常见的算法思路,并分析其复杂度:

  1. 双指针
    • 使用两个指针,一个从左到右找到第一个黑色球的位置,另一个从右到左找到第一个白色球的位置,然后交换它们。
    • 然而,这个方法在最坏情况下仍需要 O(n) 的时间来遍历整个字符串,而且每次交换操作的次数和复杂度会增加。
#include <stdio.h>
#include <string.h>

long long minimumStepsTwoPointers(char* s) {
    int n = strlen(s);
    int left = 0, right = n - 1;
    long long res = 0;

    while (left < right) {
        while (left < n && s[left] == '0') left++;
        while (right >= 0 && s[right] == '1') right--;
        if (left < right) {
            res += (right - left);
            left++;
            right--;
        }
    }
    return res;
}

双指针

  1. 动态规划
    • 可以尝试构建一个动态规划表来记录状态转移,但这会引入额外的空间开销,而且复杂度分析会变得更复杂,可能不如贪心策略直接有效。
// 动态规划不太会
  1. 前缀和后缀数组
    • 构建前缀和后缀数组来记录每个位置的黑色球数量,这样可以在常数时间内计算出每个位置的移动步数。但构建这些数组需要额外的 O(n) 空间,不如贪心策略简洁。
#include <stdio.h>
#include <string.h>

long long minimumStepsPrefixSuffix(char* s) {
    int n = strlen(s);
    int prefix[n + 1];
    int suffix[n + 1];
    memset(prefix, 0, sizeof(prefix));
    memset(suffix, 0, sizeof(suffix));

    for (int i = 1; i <= n; i++) {
        prefix[i] = prefix[i - 1] + (s[i - 1] == '1');
    }

    for (int i = n - 1; i >= 0; i--) {
        suffix[i] = suffix[i + 1] + (s[i] == '0');
    }

    long long res = 0;
    for (int i = 0; i < n; i++) {
        if (s[i] == '0') {
            res += prefix[i];
        }
    }

    return res;
}

前缀和

结论

综上所述,当前的贪心策略已经是最优解,无论是时间复杂度还是空间复杂度都是最优的,无法进一步优化。

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

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

相关文章

网工内推 | 网络运维工程师,H3CIE认证优先,13薪,享股票期权

01 畅读 &#x1f537;招聘岗位&#xff1a;高级网络运维工程师 &#x1f537;职责描述&#xff1a; 1.负责线上业务网络技术运维工作&#xff0c;保障并优化线上网络质量&#xff1b; 2.规划并构建公司线上业务网络架构&#xff1b; 3.规划线上业务网络质量评估与监控体系&…

信号:干扰类别及特征提取

目录 第一部分&#xff1a;干扰类别 1.压制干扰 1.1噪声调幅瞄准式干扰(单音干扰) 1.2噪声调频阻塞式干扰&#xff08;宽带噪声干扰&#xff09; 1.3噪声调频扫频式干扰&#xff08;线性调频&#xff09; 2.欺骗干扰 2.1距离欺骗干扰&#xff08;幅度调制干扰&#xff0…

关于main函数参数列表的那些事

写在最前面&#xff1a; 本篇博客所写代码&#xff0c;全部都依赖于Linux环境。 在开始之前&#xff0c;我们先问自己几个问题&#xff1a; main函数可以传参吗?如果main函数可以传参&#xff0c;最多可以传几个参数。main函数传递的参数具体作用是什么&#xff1f; 一.是否…

java小游戏-坦克大战1.0

文章目录 游戏界面样式游戏需求分析设计类过程1&#xff1a;初始化界面过程2&#xff1a;用面向对象思想设置功能过程3&#xff1a;调用类实例化对象过程4&#xff1a;联合调试 项目代码下载&#xff1a; CSDN_java小游戏-坦克大战1.0 来源&#xff1a;该游戏来自尚学堂~&…

神了,Suno创作的《不期待》三个版本,你最喜欢哪一个?

Suno AI 最近尝试了下 Suno AI 的v3.5模型&#xff0c;有点惊艳 做了三首版本的AI歌曲&#xff0c;词是我写的&#xff0c;其他全都交给Suno了&#xff0c;欢迎大家来听听 B站链接 Youtube链接

源码文章上传无忧,论坛小程序支持

前言 在数字化时代&#xff0c;知识的分享与传播显得愈发重要。为了满足广大创作者和求知者的需求&#xff0c;我们推出了全新的论坛小程序&#xff0c;不仅支持文章、源码、链接等多样化内容的上传&#xff0c;还实现了付费观看功能&#xff0c;为创作者们提供了一个展示才华…

flask 之JWT认证实现

目录 1、JWT 1.1、JWT概述 1.2、token的生成 1.3、token校验 1.4、flask项目中实现JWT认证 1、JWT 1.1、JWT概述 JWT&#xff08;JSON Web Token&#xff09;是一种用于身份验证和授权的开放标准。它由三部分组成&#xff0c;分别是头部、负载和签名。 头部&#xff0…

第三方软件测试机构与CMA、CNAS资质

第三方软件测试机构 随着信息技术的快速发展&#xff0c;软件在各个领域的应用越来越广泛&#xff0c;软件的质量和安全性成为人们关注的焦点。为了确保软件的质量和安全性&#xff0c;第三方软件测试机构和CMA、CNAS资质成为了重要的保障。 第三方软件测试机构是独立于软件开…

python调用excel的demo

在本地安装Pycharm之后&#xff0c;新建工程&#xff0c;在main.py中键入如下代码,即可实现Python调用excel&#xff1a; import pandas as pd sheet pd.read_excel(test.xlsx) data sheet.loc[0].values print("读取指定行的数据:\n{0}".format(data)) 第一次编…

如何将 MySQL 数据库共享给他人?

文章目录 共享所有数据库给他人1. 连接到 MySQL 数据库2. 选择要使用的数据库3. 修改连接所需的 host4. 刷新权限 共享部分数据库给他人1. 创建用户2. 授权3. 刷新权限 结语 &#x1f389;欢迎来到Java学习路线专栏~探索Java中的静态变量与实例变量 ☆* o(≧▽≦)o *☆嗨~我是I…

JVMの静、动态绑定异常捕获JIT即时编译

在说明静态绑定和动态绑定之前&#xff0c;我们首先要了解在字节码指令的层面&#xff0c;JVM是如何调用方法的&#xff1a; 例如我有以下的代码&#xff0c;很简单就是在main方法中调用了另一个静态方法&#xff1a; public class MethodTest {public static void main(Strin…

git clone 文件名中文、有冒号等问题 fatal: repository ‘***/r/鏍″洯鏅烘収椋熷爞/.git/‘ not found

记录一个git问题&#xff0c;比较有意思&#xff0c;也比较难找。 背景 首先把代码拉下来&#xff0c;发现给我报错。 怀疑 刚开始以为是仓库地址变了&#xff0c;但是发现仓库地址并没有变过。 交流 然后寻找解决方案。因为同事也遇到过&#xff0c;同事交了我一招&…

数据结构第三篇【链表的相关知识点一及在线OJ习题】

数据结构第三篇【链表的相关知识点一及在线OJ习题】 链表链表的实现链表OJ习题顺序表和链表的区别和联系 本文章主要讲解关于链表的相关知识&#xff0c;喜欢的可以三连喔 &#x1f600;&#x1f603;&#x1f604;&#x1f604;&#x1f60a;&#x1f60a;&#x1f643;&#…

【iOS】——Runtime学习

文章目录 一、Runtime介绍二、Runtime消息传递三、实例对象、类对象、元类对象四、isa_t结构体的具体实现五、cache_t的具体实现六、class_data_bits_t的具体实现七、Runtime消息转发动态方法解析备用接收者完整消息转发 一、Runtime介绍 iOS的Runtime&#xff0c;通常称为Obj…

GitHub飙升!京东认证的“Python编程入门三剑客”究竟好在哪?

Python凭借着简单易学、功能强大&#xff0c;已经跃居TIOB编程语言榜首&#xff0c;并且已经开始了它的霸榜之旅。如何选择一套适合自己的Python学习教程&#xff0c;是每个Python爱好者面临的首要问题。 今天给小伙伴们带来的是图灵&京东认证的“Python编程入门三剑客”&…

项目:仿RabbitMQ实现的消息队列组件

文章目录 写在前面开源仓库和项目上线其他文档说明 需求分析BrokerServer交换机类型持久化消息应答 模块划分服务端模块客户端模块交换机数据管理模块队列数据管理模块绑定数据管理模块消息数据管理模块队列信息管理模块虚拟机数据管理模块路由匹配模块消费者管理模块信道管理模…

gomail发送邮件的参数如何设置?如何使用?

gomail发送邮件的认证方式有哪些&#xff1f;怎么设置邮件发信&#xff1f; Gomail是一个常用的Go语言邮件发送库&#xff0c;它提供了简单易用的接口&#xff0c;使得邮件发送变得非常方便。AokSend将详细介绍如何设置gomail发送邮件的参数&#xff0c;帮助开发者更好地理解和…

Java实现经纬度坐标转换

一、坐标系统简介 坐标系统&#xff0c;是描述物质存在的空间位置&#xff08;坐标&#xff09;的参照系&#xff0c;通过定义特定基准及其参数形式来实现。 坐标是描述位置的一组数值&#xff0c;按坐标的维度一般分为一维坐标&#xff08;公路里程碑&#xff09;和二维坐标…

申请HTTPS证书的具体步骤是什么?

在当今数字化时代&#xff0c;网络安全已成为企业和个人关注的焦点。HTTPS证书作为网络安全的重要组成部分&#xff0c;不仅象征着网站的安全性&#xff0c;更是数据保护和用户信任的基石。本文将详细阐述HTTPS证书的重要性以及如何申请和配置HTTPS证书&#xff0c;以帮助网站所…

24、Linux网络端口

Linux网络端口 1、查看网络接口信息ifconfig ens33 eth0 文件 ifconfig 当前设备正在工作的网卡&#xff0c;启动的设备。 ifconfig -a 查看所有的网络设备。 ifconfig ens33 查看指定网卡设备。 ifconfig ens33 up/down 对指定网卡设备进行开关 基于物理网卡设备虚拟的…