「Swift 实战」如何高效统计 1 到 n 之间出现的 “1“?

news/2025/3/24 7:52:49/

在这里插入图片描述
在这里插入图片描述

摘要

数字 “1” 在我们的生活中无处不在,但如果让你数一数 0n 之间出现了多少次 “1”,你会怎么做?是一个个遍历,还是有更聪明的方法?这篇文章会带你用 Swift 解决这个问题,而且是 超高效 的方法!

问题描述

想象一下,你在做一些数据分析,比如:

  • 想统计车牌号码里 “1” 出现的次数
  • 想分析某个网站用户 ID 里 “1” 的分布情况
  • 研究彩票号码,看 “1” 这个数字的频率

如果 n 很小,我们还能手动数一数,但 n 一旦变大,比如 1,000,000,000,手动统计就完全不现实了。那该怎么办呢?

常见思路

最容易想到的方法是 暴力遍历

swift">var count = 0
for i in 0...n {count += String(i).filter { $0 == "1" }.count
}

看起来没毛病,但如果 n = 1,000,000,000,代码可能要跑到明天早上。效率太低,完全不行。

有没有更快的方法?当然有!

高效解法:逐位分析

我们可以不去 一个个数 “1” 的次数,而是分析 每一位 里 “1” 的贡献,快速得出最终答案。

Swift 代码

swift">func countDigitOne(_ n: Int) -> Int {var count = 0var factor = 1var currentN = nwhile currentN > 0 {let lower = n % factor          // 当前位以下的数字let digit = (n / factor) % 10   // 当前位的数字let higher = n / (factor * 10)  // 当前位以上的数字if digit == 0 {count += higher * factor} else if digit == 1 {count += higher * factor + lower + 1} else {count += (higher + 1) * factor}factor *= 10currentN /= 10}return count
}

代码解析

假设 n = 3156,我们从个位开始逐位分析:

  • 个位:统计 0-3156个位是 “1” 的情况
  • 十位:统计 0-3156十位是 “1” 的情况
  • 百位:统计 0-3156百位是 “1” 的情况
  • 千位:统计 0-3156千位是 “1” 的情况

在分析某一位的贡献时,我们把 n 拆成三部分:

  • higher:当前位的高位部分
  • digit:当前位的数字
  • lower:当前位的低位部分

不同情况下:

  • 如果 digit == 0,说明这一位不会贡献额外的 “1”,那么 “1” 的次数就是 higher * factor
  • 如果 digit == 1,那么除了 higher * factor 这个基本贡献外,还要加上 lower + 1,因为这些数字也会贡献 “1”
  • 如果 digit > 1,那么当前位的 “1” 贡献就是 (higher + 1) * factor

这个算法的 时间复杂度是 O(log n),比暴力遍历快得多。

示例测试及结果

swift">let solution = Solution()
print(solution.countDigitOne(13))  // 输出: 6
print(solution.countDigitOne(0))   // 输出: 0
print(solution.countDigitOne(100)) // 输出: 21

来看下具体的结果:

  • n = 13,出现的 “1”:1, 10, 11, 12, 13,总共 6 次
  • n = 100,出现的 “1”:1, 10-19, 21, 31, ..., 91, 100,总共 21 次

可以看到,这个方法不仅正确,而且 快得飞起

复杂度分析

  • 时间复杂度:O(log n),因为我们按 位数 进行计算,每次循环去掉一位数字
  • 空间复杂度:O(1),只用了几个整数变量,没开额外的数组或数据结构

总结

这道题的核心是 逐位拆解法,不用一个个数 “1”,而是分析每一位对结果的贡献,从而大幅提高计算效率。

这个方法适用于 大规模数字统计 场景,比如:

  • 统计电话号码、身份证号等数据里的 “1”
  • 研究彩票、车牌号码里某个数字的分布
  • AI 数据分析,看看某些 ID 里 “1” 出现的概率

如果你以后遇到类似的 大数据统计问题,不妨试试这个方法。希望这篇文章能帮到你!


http://www.ppmy.cn/news/1581413.html

相关文章

使用PyTorch Lightning进行深度学习模型训练

哈喽,大家好,我是木头左! 一、PyTorch Lightning简介 1.1 什么是PyTorch Lightning? PyTorch Lightning是一个用于简化深度学习模型训练过程的框架。它提供了一种高层次的抽象,使得用户可以专注于模型的定义和业务逻辑,而无需处理繁琐的训练细节。 1.2 PyTorch Lightn…

高端网站设计:艺术与科技的完美融合,引领数字新风尚

在浩瀚的数字海洋中,网站如同一座座灯塔,指引着用户前往他们所需的信息彼岸。而在这众多灯塔中,有一类尤为璀璨夺目,那便是高端网站设计。它们不仅承载着信息的传递功能,更是艺术与科技完美融合的典范,以独…

docker compose启动ollama+openweb ui,本地大模型十分钟搭建,速度主要取决于网速

文章目录 前言wsl2 docker官方教程安装wsl2安装 Linux 发行版设置 Windows Terminal设置 Linux 用户名和密码WSL 与 Windows Terminal 配合使用wsl其他Ubuntu 更新和升级包文件存储运行 Linux GUI 应用VS Code 和 WSL 扩展 安装 Docker Desktop使用 Docker 设置远程开发容器 o…

NLP高频面试题(八)——GPT三个版本的区别

GPT三大版本的区别解析 GPT(Generative Pre-trained Transformer)系列是由OpenAI开发的一系列自然语言处理模型,旨在通过大规模数据训练,生成具有强大语言理解和生成能力的AI系统。从最初的GPT-1到目前的GPT-3,每一代…

西门子 PLC 串口转网口模块

一、功能概述 本文档是西门子 PLC 串口转以太网系列产品说明书,包含 SG-S7-200-ETH、 S7-200-ETH(2P) ,SG-S7-300-ETH ,SG-S7-300-ETH(2P)共四个产品。使用框图 如下图所示意。 1.1 产品功能 本系列产品用来给西门子 S7-200/300 PLC 串口扩…

使用FastAPI为知识库问答系统前端提供后端功能接口

后端接口实现以及接口调用的类代码一览 1. 后端接口代码2. 代码结构概述3. 主要功能模块1. 跨域支持2. 用户登录接口(/login)3. 用户注册接口(/register)4.用户相关接口依赖的类5.聊天接口(/chat)6.聊天接口依赖的类 4. 连接方式 1. 后端接口代码 # app.py from fastapi impor…

Ubuntu sudo apt-get install 出现“E: 无法定位软件包问题”解决方法

方法1.使用sudo apt-get update 方法2.更换镜像源 清华源地址:清华源地址https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/ Ubuntu的软件配置文件是/etc/apt/sources.list 更换源的时候需要先对其进行备份再更换 步骤如下: 1.切换到镜像源的位置…

cursor无限续杯软件操作教程

软件使用教程: 在这里插入图片描述 软件界面: 破解流程: 1.退出 cursor 软件的账号,点击 log out 按钮,可以手动退出并关闭软件。 2.删除账号,点击按钮会自动打开网页,手动删除即可。 3.确保…