数学(三) -- LC[1010][1015] 可被 K 整除的最小整数

news2024/9/22 15:51:19

1 可被 K 整除的最小整数

1.1 题目描述

        题目链接:https://leetcode.cn/problems/smallest-integer-divisible-by-k/description/

1.2 思路分析

模运算

        如果让你计算 1234 ⋅ 6789 1234 \cdot 6789 12346789 的个位数,你会如何计算?

        由于只有个位数会影响到乘积的个位数,那么 4 ⋅ 9 = 36 4\cdot 9=36 49=36 的个位数 6 6 6 就是答案。

        对于 1234 + 6789 1234+6789 1234+6789 的个位数,同理, 4 + 9 = 13 4+9=13 4+9=13 的个位数 3 3 3 就是答案。

        你能把这个结论抽象成数学等式吗?

        一般地,涉及到取模的题目,通常会用到如下等式(上面计算的是 m = 10 m=10 m=10):

( a + b )   m o d   m = ( ( a   m o d   m ) + ( b   m o d   m ) )   m o d   m ( a ⋅ b )   m o d   m = ( ( a   m o d   m ) ⋅ ( b   m o d   m ) )   m o d   m (a+b)\bmod m = ((a\bmod m) + (b\bmod m)) \bmod m \\ (a\cdot b) \bmod m=((a\bmod m)\cdot (b\bmod m)) \bmod m (a+b)modm=((amodm)+(bmodm))modm(ab)modm=((amodm)(bmodm))modm

        证明:根据带余除法,任意整数 a a a 都可以表示为 a = k m + r a=km+r a=km+r,这里 r r r 相当于 a   m o d   m a mod m amodm。那么设 a = k 1 m + r 1 ,   b = k 2 m + r 2 a=k_1m+r_1,\ b=k_2m+r_2 a=k1m+r1, b=k2m+r2

第一个等式:
( a + b )   m o d   m = ( ( k 1 + k 2 ) m + r 1 + r 2 )   m o d   m = ( r 1 + r 2 )   m o d   m = ( ( a   m o d   m ) + ( b   m o d   m ) )   m o d   m \begin{aligned} &(a+b) \bmod m\\ =&((k_1+k_2) m+r_1+r_2)\bmod m\\ =&(r_1+r_2)\bmod m\\ =&((a\bmod m) + (b\bmod m)) \bmod m \end{aligned} ===(a+b)modm((k1+k2)m+r1+r2)modm(r1+r2)modm((amodm)+(bmodm))modm

        即:两个数相加对某个数求余等于两个数分别求余相加之后再求余。

第二个等式:
( a ⋅ b )   m o d   m = ( k 1 k 2 m 2 + ( k 1 r 2 + k 2 r 1 ) m + r 1 r 2 )   m o d   m = ( r 1 r 2 )   m o d   m = ( ( a   m o d   m ) ⋅ ( b   m o d   m ) )   m o d   m \begin{aligned} &(a\cdot b) \bmod m\\ =&(k_1k_2m^2+(k_1r_2+k_2r_1)m+r_1r_2)\bmod m\\ =&(r_1r_2)\bmod m\\ =&((a\bmod m)\cdot (b\bmod m)) \bmod m \end{aligned} ===(ab)modm(k1k2m2+(k1r2+k2r1)m+r1r2)modm(r1r2)modm((amodm)(bmodm))modm

举例一: k = 7 k = 7 k=7

        从小到大枚举 n n n,第一个能被 k k k 整除的数的长度即为答案。

1 → 11 → 111 → 1111 → 11111 → 111111 1 \rightarrow 11 \rightarrow 111 \rightarrow 1111 \rightarrow 11111 \rightarrow 111111 111111111111111111111

        根据前置知识,设 x x x 是上一次运算的结果(初始为1),则下一个 n n n k k k 的结果为 ( 10 x + 1 ) m o d k (10x + 1) mod k (10x+1)modk,看它是否为0。

1 → 4 ⟶ 6 ⟶ 5 ⟶ 2 ⟶ 0 1 \rightarrow 4 \longrightarrow 6 \longrightarrow 5 \longrightarrow 2 \longrightarrow 0 146520

举例二: k = 24 k=24 k=24

        如果计算结果和之前的某个数相同,由于计算规则不变,后面会无限重复下去,无法得到0。

方法一:哈希表

        用哈希表记录计算结果。如果在算出0之前就遇到了在哈希表中的数字,则返回-1。

class Solution:
    def smallestRepunitDivByK(self, k: int) -> int:
        x = 1 % k           #  x 为余数
        seen = set()        #  创建一个无序集合,用于存储余数
        while x and x not in seen:      # 当余数为0或者余数重复出现,退出循环
            seen.add(x)
            x = (10 * x + 1) % k
        return -1 if x else len(seen) + 1   # 余数不为0,返回-1,余数为0,返回len(seen)+1    

复杂度分析

  • 时间复杂度: O ( k ) \mathcal{O}(k) O(k)
  • 空间复杂度: O ( k ) \mathcal{O}(k) O(k)

方法二:抽屉原理

        循环 k k k 次,如果没有算出0,则返回-1。为什么?模 k k k 的结果在 [ 0 , k − 1 ] [0, k-1] [0,k1] 中,这有 k k k 个数字。如果循环 k k k 次还没有找到0,根据鸽巢原理(抽屉原理),必然有重复的数字。这也同时说明算法一的时间复杂度为 O ( k ) O(k) O(k)

class Solution:
    def smallestRepunitDivByK(self, k: int) -> int:
        if k % 2 == 0 or k % 5 == 0:
            return -1
        x = 1 % k
        for i in count(1):              # 一定有解
            if x == 0:
                return i
            x = (x * 10 + 1) % k

复杂度分析

  • 时间复杂度: O ( k ) \mathcal{O}(k) O(k)
  • 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1),仅用到若干额外变量。

itertools.count(start=0, step=1)

        创建一个迭代器,它从 start 值开始,返回均匀间隔的值。常用于 map() 中的实参来生成连续的数据点。此外,还用于 zip() 来添加序列号。大致相当于:

def count(start=0, step=1):
    # count(10) --> 10 11 12 13 14 ...
    # count(2.5, 0.5) --> 2.5 3.0 3.5 ...
    n = start
    while True:
        yield n
        n += step

        当对浮点数计数时,替换为乘法代码有时精度会更好,例如:(start + step * i for i in count())

方法三:数学推导

        设 n n n 的长度为 x x x,那么 n = 1 0 x − 1 9 n=\frac{10^x-1}{9} n=910x1 n n n k k k 的倍数,等价于 1 0 x − 1 10^x-1 10x1 9 k 9k 9k 的倍数,即 1 0 x ≡ 1 ( m o d 9 k ) 10^x \equiv 1(mod 9k) 10x1(mod9k)

  • 结论:最小的 x x x 必然是 ϕ ( 9 k ) \phi(9k) ϕ(9k) 的因子。
  • 反证:如果 ϕ ( 9 k ) = p x + r ( 0 < r < x ) \phi(9k) = px + r (0 < r <x) ϕ(9k)=px+r(0<r<x),根据欧拉定理, 1 0 ϕ ( 9 k ) = ( 10 ) P ﹒ 10 ” = 10 ” = 1 ( m o d 9 k ) 10^{\phi(9k)}=(10)P﹒10”=10”= 1(mod 9k) 10ϕ(9k)=(10)P﹒10”=10”=1(mod9k),这说明有一个比 x x x 更小的 r r r,矛盾。

        那么计算 ϕ ( 9 k ) \phi(9k) ϕ(9k) 并枚举其因子 d d d,用快速幂判断 1 0 d m o d ( 9 k ) 10^d mod (9k) 10dmod(9k) 是否等于1。这一做法只需要 ( ( k ) l o g k ) (\sqrt(k)log k ) (( k)logk) 的时间。

一点优化

        由于 n n n 的个位数是1,所以必然不是 2 的倍数和 5 的倍数。如果 k k k 是 2 的倍数或 5 的倍数,那么必然无解,返回 —1。否则一定有解。

        证明:根据算法二,在计算过程中必然会出现两个数模 k k k 同余。设这两个数为 a = 1 0 x − 1 9 a=\frac{10^x-1}{9} a=910x1 b = 1 0 y − 1 9 b=\frac{10^y-1}{9} b=910y1,且 a > b a > b a>b。那么 a − b a-b ab k k k 的倍数。

        注意 a − b = 1 0 x − 1 0 y 9 = 1 0 y ⋅ 1 0 x − y − 1 9 a-b=\frac{10^x-10^y}{9}=10^y\cdot\frac{10^{x-y}-1}{9} ab=910x10y=10y910xy1 k k k在没有因子 2 和 5 的情况下,要想整除上式,必须要整除 1 0 x − y − 1 9 \frac{10^{x-y}-1}{9} 910xy1,这说明 n n n 的长度可以是 x − y x-y xy

# 计算欧拉函数(n 以内的与 n 互质的数的个数)
def phi(n: int) -> int:
    res = n
    i = 2
    while i * i <= n:
        if n % i == 0:
            res = res // i * (i - 1)
            while n % i == 0:
                n //= i
        i += 1
    if n > 1:
        res = res // n * (n - 1)
    return res

class Solution:
    def smallestRepunitDivByK(self, k: int) -> int:
        if k % 2 == 0 or k % 5 == 0:
            return -1
        m = phi(k * 9)
        # 从小到大枚举不超过 sqrt(m) 的因子
        i = 1
        while i * i <= m:
            if m % i == 0 and pow(10, i, k * 9) == 1:
                return i
            i += 1
        # 从小到大枚举不低于 sqrt(m) 的因子
        i -= 1
        while True:
            if m % i == 0 and pow(10, m // i, k * 9) == 1:
                return m // i
            i -= 1

复杂度分析

  • 时间复杂度: O ( k log ⁡ k ) \mathcal{O}(\sqrt{k}\log k) O(k logk)。计算 ϕ ( 9 k ) \phi(9k) ϕ(9k) 和枚举 ϕ ( 9 k ) \phi(9k) ϕ(9k) 的因子都需要 O ( k ) \mathcal{O}(\sqrt{k}) O(k ) 的时间,对每个因子计算快速幂需要 O ( log ⁡ k ) \mathcal{O}(\log k) O(logk) 的时间,所以时间复杂度为 O ( k log ⁡ k ) \mathcal{O}(\sqrt{k}\log k) O(k logk)
  • 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)。仅用到若干额外变量。

2 总持续时间可被 60 整除的歌曲

2.1 题目描述

        题目链接:https://leetcode.cn/problems/pairs-of-songs-with-total-durations-divisible-by-60/description/

2.2 思路分析

1. 组合数学

        遍历数组的同时用一个哈希表(或者数组)记录元素的出现次数。

        遍历 time \textit{time} time

  • 举例,如果 time [ i ] = 1 \textit{time}[i]=1 time[i]=1,那么需要知道左边有多少个模 60 余数是 59 的数。
  • 举例,如果 time [ i ] = 62 \textit{time}[i]=62 time[i]=62,那么需要知道左边有多少个模 60 余数是 58 的数。
  • 一般地,对于 time [ i ] \textit{time}[i] time[i],需要知道左边有多少个模 60 余数是 60 − time [ i ] m o d 60 60-\textit{time}[i] mod 60 60time[i]mod60 的数。
    特别地,如果 time [ i ] \textit{time}[i] time[i] 模 60 的余数是 0,那么需要知道左边有多少个模 60 余数也是 0 的数。
    这两种情况可以合并为:累加左边 ( 60 − time [ i ] m o d 60 ) m o d 60 (60-\textit{time}[i] mod 60) mod 60 (60time[i]mod60)mod60 的出现次数。

        代码实现时,用一个长为 60 的数组 cnt \textit{cnt} cnt 维护 time [ i ] m o d 60 \textit{time}[i] mod 60 time[i]mod60 的出现次数。

class Solution:
    def numPairsDivisibleBy60(self, time: List[int]) -> int:
        ans = 0
        cnt = [0] * 60
        for t in time:
            # 先查询 cnt,再更新 cnt,因为题目要求 i<j
            # 如果先更新,再查询,就把 i=j 的情况也考虑进去了
            ans += cnt[(60 - t % 60) % 60]
            cnt[t % 60] += 1
        return ans

复杂度分析

  • 时间复杂度: O ( n + U ) \mathcal{O}(n+U) O(n+U),其中 n n n nums \textit{nums} nums 的长度, U = 60 U=60 U=60
  • 空间复杂度: O ( U ) \mathcal{O}(U) O(U)

参考

  • 三种算法+优化:https://leetcode.cn/problems/smallest-integer-divisible-by-k/solutions/2263780/san-chong-suan-fa-you-hua-pythonjavacgo-tk4cj/
  • 「两数之和」的本质是什么?:https://leetcode.cn/problems/pairs-of-songs-with-total-durations-divisible-by-60/solutions/2259343/liang-shu-zhi-he-de-ben-zhi-shi-shi-yao-bd0r1/

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

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

相关文章

c高级day2

#include <stdio.h> #include <stdlib.h> #include <string.h>int arrMAX_1(void *p,int n,int m,int x,int y); int arrMAX_2(void *p,int n,int m,int x,int y); int main(int argc, const char *argv[]) {int n0,m0;printf("请输入行数i 列数j\n&quo…

Baumer工业相机堡盟工业相机如何进行多个工业相机IP地址配置

Baumer工业相机堡盟工业相机如何进行多个工业相机IP地址配置 Baumer工业相机Baumer工业相机进行多相机IP配置的技术背景Baumer工业相机如何进行多相机IP配置1.配置Baumer工业相机连接的PC端IP地址2.配置Baumer工业相机的IP地址 Baumer工业相机 Baumer工业相机堡盟相机是一种高…

R 中的探索性相关分析

动动发财的小手&#xff0c;点个赞吧&#xff01; 本文[1] 相关分析是探索两个或多个变量之间关系的最基本和最基础的方法之一。您可能已经在某个时候使用 R 执行过相关分析&#xff0c;它可能看起来像这样&#xff1a; cor_results <- cor.test(my_data$x, my_data$y, …

手机上调试pc端电脑上的项目

文章目录 前言1、window r 打开电脑命令窗口并输入cmd点击确定或者敲击回车键2、在cmd命令行面板上输入ipconfig获取本电脑的ip地址3、在手机浏览器中输入http://192.168.XX.XX:8080 即可 前言 手机上调试电脑运行的项目的前提条件是手机和电脑公用一个局域网&#xff08;也就…

APP 性能优化你掌握的怎么样?简单聊聊?

产品性能是每个技术团队比较关心的一件事&#xff0c;不管是产品上线前到上线后&#xff0c;都需要对产品进行性能监控和优化&#xff0c;如果产品在运行过程中出现了问题&#xff0c;是很影响用户的体验感受。 所以在一些大厂技术团队中&#xff0c;是非常看重个人性能优化的…

面向开发人员的 ChatGPT 提示词教程中文版

面向开发人员的 ChatGPT 提示词教程中文版 1. 指南1-1. 提示的指南1-2. 配置1-3. 提示语原则原则 1: 写出清晰而具体的指示技巧 1: 使用分隔符来清楚地表明输入的不同部分技巧 2: 要求提供结构化的输出技巧 3: 要求模型检查条件是否得到满足技巧 4: "少许样本"提示 原…

为你推荐一款最好用的免费截图工具-Snipaste,截图高清、智能模糊还支持滚动长截图!!!

写文章经常需要插入截图&#xff0c; 但是常常很难有顺手的截图工具&#xff0c; 常见的难题是&#xff1a; 很难滚动长屏截图&#xff0c; 截图中马赛克处理很麻烦&#xff0c; 输出的截图图像质量差。 经过大量的工具使用对比&#xff0c; 这里推荐一个最好用的截图工具。 Sn…

Fotran学习:chapter8函数

1.子程序(subrountine)的使用 把常常用于使用、具有特定功能的程序代码独立出来&#xff0c;封装程子程序&#xff0c;以后调用使用call即可。 program chapter4_exercise !主程序implicit nonecall sub1()call sub2()pauseend program chapter4_exercisesubroutine sub1() !子…

产品经理制,互联网公司发扬光大的

产品经理制&#xff0c;在互联网公司发扬光大 张小龙被称作&#xff1a;七星产品经理 其实&#xff0c;中小企业老板基本是首席产品经理 趣讲大白话&#xff1a;像带孩子一样做产品 【趣讲信息科技160期】 **************************** 产品经理制核心问题解决的是&#xff1a…

STM32F4_随机数发生器(RNG)

目录 1. 随机数发生器RNG是什么 2. RNG随机发生器框图 3. 运行RNG 4. RNG寄存器 4.1 RNG控制寄存器&#xff1a;RNG_CR 4.2 RNG状态寄存器&#xff1a;RNG_SR 4.3 RNG数据寄存器&#xff1a;RNG_DR 5. 库函数配置随机数发生器 6. 实验程序 6.1 main.c 6.2 RNG.c 6.…

植物奶站上风口

不知不觉间&#xff0c;植物奶无处不在。逛街&#xff0c;便利店里有燕麦奶、椰奶、豆奶&#xff0c;星巴克、肯德基有燕麦拿铁&#xff1b;打开小红书&#xff0c;有人做各种植物奶产品的测评结果&#xff0c;有人分享优质植物奶的自制方法…… 这场“风”并非空穴而来。 一…

软件工程开发文档写作教程(07)—招投标文件写作规范

本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl本文参考资料&#xff1a;电子工业出版社《软件文档写作教程》 马平&#xff0c;黄冬梅编著 招投标文件概述 国内的软件项目招投标文件的写作规则并不存在行业标准。许多大型企业的信息…

面向开发人员的 ChatGPT 提示词教程 - ChatGPT Prompt Engineering for Developers

面向开发人员的 ChatGPT 提示词教程 - ChatGPT Prompt Engineering for Developers 1. 指南(原文: Guidelines)1-1. 提示的指南(原文: Guidelines for Prompting)1-2. 配置1-3. 提示语原则(原文: Prompting Principles)原则 1: 写出清晰而具体的指示(原文: Write clear and spe…

【近期解决的小问题】

文章目录 写在前面1. Win10中USB转串口设备安装完成驱动显示感叹号&#xff08;USB不能用&#xff09;背景尝试过的方法其他解决方法 2. 安装Win7虚拟机“缺少所需的CD/DVD驱动器设备驱动程序”背景尝试过的方法 3. WMware安装Kali Linux后黑屏左上角光标闪烁背景尝试过的方法 …

Java设计模式 12-模版模式

模板模式 一、豆浆制作问题 编写制作豆浆的程序&#xff0c;说明如下: 1)制作豆浆的流程 选材—>添加配料—>浸泡—>放到豆浆机打碎 2)通过添加不同的配料&#xff0c;可以制作出不同口味的豆浆 3)选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一…

关于使用SSM框架搭建的项目的运行方法

目录 运行环境配置 1、安装 IDEA 开发工具 中文版设置 JDK直接下载 2、安装 MYSQL 数据库 2.1 下载安装 2.2 配置环境变量 2.4 安装 MySQL 2.4 进入 MySQL 2.5 常见问题 3、安装Tomcat 4、IDEA配置MYSQL 4.1、常见错误 5、IDEA配置TOMCAT 5.1、常见报错 一 运行环…

2023年最新无脑安装 Go lang 环境配置并编写、运行、打包第一个 Golang 程序详细步骤,附带图文教程

文章目录 下载安装Golang配置 Golang 环境GO111MODULEGOPROXY开启 Go mod 模式及设置包下载国内镜像配置 Vscode Golang 环境 Bug 集锦The "gopls" command is not available.Run "go get -v golang.org/x/tools/gopls" to install. GO语言也称为Golang&am…

烽火HG680-J/V-Hi3798MV100-当贝纯净桌面-卡刷固件包

烽火HG680-J&#xff0f;V-Hi3798MV100-当贝纯净桌面-卡刷固件包 特点&#xff1a; 1、适用于对应型号的电视盒子刷机&#xff1b; 2、开放原厂固件屏蔽的市场安装和u盘安装apk&#xff1b; 3、修改dns&#xff0c;三网通用&#xff1b; 4、大量精简内置的没用的软件&…

【ArcGIS教程】批量裁剪

ArcGIS教程&#xff1a;批量裁剪 1 裁剪1.1 准备&#xff1a;创建shp文件/选定区域、自由选区1.1 单一裁剪1.2 批量裁剪&#xff08;Batch&#xff09; 2 批量裁剪参考 1 裁剪 1.1 准备&#xff1a;创建shp文件/选定区域、自由选区 步骤1&#xff1a; 创建shp文件 打开ArcCat…

2023年了,来体验下前端的测试方案

在当前的前端当中&#xff0c;有好多同学自己写的代码bugger横飞&#xff0c;怎么解决这个问题呢&#x1f914;&#x1f914;&#x1f914;&#xff1f;个人觉得主要有以下两个趋势 给前端的代码加上类型检查&#xff08;ts&#xff09;给前端代码编写单元测试和e2e测试 当然&a…