2938. 区分黑球与白球

题目

桌子上有 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;
}

前缀和

结论

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode:电话号码的字母组合

题目链接&#xff1a;17. 电话号码的字母组合 - 力扣&#xff08;LeetCode&#xff09; 普通版本&#xff08;回溯&#xff09; class Solution { public:string tmp;//临时存放尾插内容vector<string> res;//将尾插好的字符串成组尾插给resvector<string> board{…

⌈ 传知代码 ⌋ AI驱动食物图像识别

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

【数据结构】平衡二叉树(AVL树)

目录 前言 一、AVL树概念 二、AVL树节点定义 三、AVL树插入 1. 按照二叉搜索树的方式插入新节点 2. 维护节点的平衡因子与调整树的结构 a. 新节点插入较高左子树的左侧---左左&#xff1a;右单旋 b. 新节点插入较高右子树的右侧---右右&#xff1a;左单旋 c. 新节点插入…

前端面试项目细节重难点(已工作|做分享)想(八)

面试官&#xff1a;请你讲讲你在该项目中遇到的印象深刻的问题是什么&#xff1f; 答&#xff1a;我的回答&#xff1a;该项目的实现过程中我确实遇到了问题&#xff1a;【我会给大家整理回答思路和角度&#xff0c;那那么遇到这样的问题也可借鉴这种思路进行阐述】 第一层面…

RocketMQ教程(五):RocketMQ的工作原理2

工作原理 RocketMQ 是一个高性能、高吞吐量的分布式消息和流计算平台,它基于发布-订阅模式工作。其核心设计理念是确保消息传递的高效性、稳定性和可扩展性。RocketMQ 的工作原理主要可以分为以下几个部分: 1. 消息流程 消息发布: Producer 首先向 NameServer 查询目标 Top…

二重,三重积分和曲面,曲线积分的关系和区别

这是我在学习完曲面曲线积分概念后容易和二重三重积分混淆而大概总结和区分了一下&#xff0c;如果有错误请大佬指出&#xff0c;多谢&#xff01;&#xff01;&#xff01;

shell(一)

shell 既是脚本语言又是应用程序 查看自己linux系统的默认解析&#xff1a;echo $SHELL 创建第一个shell 文件 touch 01.sh编辑 vi 01.sh01.sh 文件内容 #!/bin/bash echo felicia保存 按Esc 然后输入:wq 定义以开头&#xff1a;#!/bin/bash #!用来声明脚本由什么shell解释…

无线麦克风什么牌子的音质效果好?一文揭秘领夹麦克风哪个品牌好

​近年来&#xff0c;无线领夹麦克风在各个领域都大放异彩&#xff0c;无论是直播、采访还是上课&#xff0c;都能看到它的身影。这款小小的无线麦克风&#xff0c;蕴含着巨大的能量&#xff0c;为媒体人的创作提供了强大的支持。对于想要更新设备的媒体人来说&#xff0c;现在…

打造国产软硬件一体化解决方案 YashanDB与宏杉科技完成多项兼容互认证

近日&#xff0c;深圳计算科学研究院崖山数据库系统YashanDB与宏杉科技系列存储、系列服务器与数据库一体机等多款产品顺利完成兼容性互认证。经严格测试&#xff0c;双方产品完全兼容&#xff0c;稳定运行&#xff0c;共同提供高效、稳定、安全的国产软硬件一体化解决方案&…

tmux工具使用鼠标滚动窗口及分屏命令

tmux工具使用鼠标滚动窗口及分屏命令 1. tmux source配置文件 长期生效2. 临时生效3. 实现分屏 1. tmux source配置文件 长期生效 vim ~/.tmux.conf echo "set -g mouse on" > ~/.tmux.conf tmux source-file ~/.tmux.conf2. 临时生效 1. 进入到tmux命令窗口 2.…

流水线建构apk、abb实战(一)

在构建机上需要下载的工具 流水线中的构建机无法使用Android Studio中自带的sdk工具下载&#xff0c;所以得下载commandlinetools命令行工具&#xff0c;下载后使用随附的 sdkmanager 下载其他 SDK 软件&#xff0c;解压后按照/cmdline-tools/latest/bin/sdkmanager目录结构整…

【Java毕业设计】基于Java的教师考勤管理系统的设计与实现

文章目录 摘 要ABSTRACT目 录1 概述1.1 研究背景及意义1.2 国内外研究现状1.3 拟研究内容1.4 系统开发技术1.4.1 vue技术1.4.2 B/S结构1.4.3 Spring Boot框架1.4.4 MySQL数据库1.4.5 MVC模式 2 系统需求分析2.1 可行性分析2.2 功能需求分析 3 系统设计3.1 功能结构设计3.2 系统…

红酒保存中的软木塞与瓶身保护

云仓酒庄雷盛红酒&#xff0c;以其卓着的品质和精美的包装赢得了众多消费者的喜爱。在红酒的保存过程中&#xff0c;软木塞与瓶身保护是至关重要的环节。本文将深入探讨这两方面的问题&#xff0c;以帮助消费者更好地理解和欣赏云仓酒庄雷盛红酒。 首先&#xff0c;我们来谈谈软…

神经网络 torch.nn---损失函数与反向传播

torch.nn - PyTorch中文文档 (pytorch-cn.readthedocs.io) torch.nn — PyTorch 2.3 documentation Loss Function的作用 每次训练神经网络的时候都会有一个目标&#xff0c;也会有一个输出。目标和输出之间的误差&#xff0c;就是用Loss Function来衡量的。所以&#xff0c;…

美国签证办理需要带哪些材料?

在申请美国签证时&#xff0c;准备充分的材料至关重要。以下知识人网整理的关于您可能需要携带的一些常见材料&#xff1a; 1.护照&#xff1a;您的护照必须是有效的&#xff0c;并且在签证申请过程中至少有六个月的有效期。 2.签证申请表&#xff1a;您需要填写并提交签证申请…

29 - 买下所有产品的客户(高频 SQL 50 题基础版)

29 - 买下所有产品的客户 selectc.customer_id fromCustomer c group byc.customer_id havingcount(c.product_key)(select count(distinct product_key) from Product);

Windows下安装和配置Redis

目录 1、下载redis压缩包 2、解压redis文件 3、启动redis临时服务 4、打开Redis客户端进行连接 5、使用一些基础操作来测试 5.1、输入ping命令来检测redis服务器与redis客户端的连通性 5.2、使用set和get命令测试redis数据库进行数据存储和获取 5.3、在命令中通过shut…

Easy 同学:AI 时代将加速计算机专业和程序员职业的分化

一、原贴 2024 年 6 月 5 日 拥有 60多万粉丝的方糖气球&#xff08;ftqq.com&#xff09;博主 、独立开发者&#xff1a;Easy 发表了一篇 AI 对计算机专业和程序员行业影响的新浪博客&#xff0c;看后很有启发&#xff0c;故而将原文摘录于此&#xff1a; 单独开个贴说一下吧…

项目实战系列——WebSocket——websock简介

最近项目中需要用到mes和本地客户端进行实时通讯&#xff0c;本来想用webapi进行交互的&#xff0c;但是考虑到高效和实时性&#xff0c;就采用这一项技术。 以往采用的方式——长轮询 客户端主动向服务器发送一个请求&#xff0c;如果服务器没有更新的数据&#xff0c;客户端…

我的python管理

目前环境 Anaconda&#xff1a;python3.9 python2.7 IDA&#xff1a;python3.8 pycharm&#xff1a;&#xff1f;&#xff1f; 以后应该会补吧… 因为某些文件似乎用的python2决定整个python2 安装python2.7 打开anaconda命令行输入 conda create --name python27 python2…