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

2023-05-16

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/
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数学(三) -- LC[1010]&[1015] 可被 K 整除的最小整数 的相关文章

  • AT&T语法

    在linux内核编写中 为了维持与gcc输出汇编程序的兼容性 as汇编器使用AT amp T系统的V的汇编语法 下面简称为AT amp T语法 这种语法与Intel汇编程序使用的语法 简称Intel语法 很不一样 他们之间的主要区别有以下几
  • 5.ROS&PX4--offboard模式多航点代码编写

    4 ROS amp PX4 offboard模式多航点代码编写 offboard模式多航点代码编写等待更新 offboard模式多航点代码编写 等待更新 span class token comment 64 file offb node
  • 【信息奥赛题解】昆虫繁殖(详细分析题解 & C++ 代码)

    昆虫繁殖问题 x1f31f 题目名称 昆虫繁殖 题目描述 科学家在热带森林中发现了一种特殊的昆虫 xff0c 这种昆虫的繁殖能力很强 每对成虫过 X X X 个月后开始产卵 xff0c 每月产 Y Y
  • Jetseon TX2 & IntelRealsense D435i & Python

    Jetseon TX2 amp IntelRealsense D435i amp Python amp Socket 一 IntelRealsense Python Wrapper GitHub 1 Installation pip ins
  • 无人机仿真SLAM_gazebo&promethues

    无人机仿真 总体概述系统要求 PX4固件简介无人机固件整体框图无人机软件框图无人机硬件模型 Mavlink模块位置估计与姿态估计模块安装与编译二次开发 机载计算机程序控制模块估计模块仿真模块SLAM模块SLAM效果演示 总体概述 无人机仿真
  • [转&精]IO_STACK_LOCATION与IRP的一点笔记

    IO STACK LOCATION和IRP算是驱动中两个很基础的东西 xff0c 为了理解这两个东西 xff0c 找了一点资料 1 IRP可以看成是Win32窗口程序中的消息 xff08 Message xff09 xff0c DEVICE
  • 使用SP Racing F3飞控&ROSflight软件包的无人机自主飞行系统

    搭建四旋翼系统 机架 xff1a XR215 Plus 328 分线板 xff1a XR215 Plus PDB 飞控 xff1a SP Racing F3 标准版 xff08 Acro xff09 86 电机 xff1a 银燕RS2205
  • Liunx下源代码安装&&make&&makefile

    Linux下安装软件的方式分为源代码安装和二进制安装 源代码安装 xff0c 即使用应用程序源代码进行编译安装二进制安装 xff0c 例如red hat发行的 rpm包 debian发行的 deb包 源代码安装 用c语言为例 include
  • Lesson 9.2&9.3&9.4 黑箱:不可解释的深层神经网络&探索多层神经网络:层vsh(z)

    二 黑箱 xff1a 深层神经网络的不可解释性 首先从结构上来看 xff0c 多层神经网络比单层神经网络多出了 中间层 中间层常常被称为隐藏层 xff08 hidden layer xff09 xff0c 理论上来说可以有无限层 xff0c
  • 【浅墨著作】《逐梦旅程:Windows游戏编程之从零开始》勘误&配套源代码下载...

    I 39 m back 恩 xff0c 几个月不见 xff0c 大家还好吗 xff1f 这段时间真的好多童鞋在博客里留言说或者发邮件说浅墨你回来继续更新博客吧 woxiangnifrr童鞋说每天都在来浅墨的博客逛一下看有没有更新 xff0c
  • 数组名a+1和&a+1的区别

    C C 43 43 里面的数组名字会退化为指针 xff0c 所以数组名a实际指的是数组的第一个元素的地址 而数组名作为指针来讲有特殊性 xff0c 它正在它所指向的内存区域中 xff0c amp a的值和a的数值是相同的 xff08 可以输
  • Intel RealSense L515&Unreal Engine 4调试记录

    文章目录 前言一 安装与配置1 安装前置条件2 配置 二 编译与运行1 编译2 运行 填坑与测试1 填坑2 测试 前言 Intel RealSense系列推出了适用于Unreal Engine 4的相关插件 xff0c 官网提供了相关示例代
  • 【RoboMaster】舵机驱动&蓝牙模块教程

    本文是为参加2021赛季北京理工大学机器人队校内赛所写的简单教程 xff0c 意在帮助参赛选手快速了解校内赛所需模块的使用方法 xff0c 以及其与薪火培训知识的联系 舵机驱动 硬件接线 舵机是由直流电机 减速齿轮组 传感器和控制电路组成的
  • Jetson xavier Nx & jetson nano 上手 + 刷机

    本教程基于Jetson xavier Nx开发套件 本教程参考Nvidia官方刷机教程 制作启动盘 在官方下载中心下载SD卡镜像并解压 下载SD Memory Card Formatter 需要划到页面最下方 xff0c 点击 Accept
  • C++中vector作为参数的三种传参方式(传值 && 传引用 && 传指针)

    c 43 43 中常用的vector容器作为参数时 xff0c 有三种传参方式 xff0c 分别如下 xff1a function1 vector vec xff0c 传值 function2 vector amp vec xff0c 传引
  • 无人机拉力测试台研制&测试过程中的9个关键技术点

    随着近年来无人机行业的飞速迭代发展 xff0c 越来越多的相关从业人员选择使用拉力测试台来测试并优化无人机的动力系统 xff0c 本文尝试从无人机拉力测试台的研制和使用角度来阐述无人机拉力测试中的9个关键技术点 1 电磁干扰方面的考虑 测试
  • JLINK给STM32下载的两种模式--jtag & sw连线及配置

    jtag线就不说了 xff0c 将jlink的Vref GND TMS TCK分别接至SW接口 对于STM32F103RCT6来说 xff1a TMS PA12 xff0c TCK PA14 关于KEIL MDK中的设置如下图所示就可以了
  • SIP 鉴权 & HTTP 认证

    sip 鉴权是基于摘要签名认证的 具体来说 每一个用户都有一个用户名和密码 用户名和密码在客户端和SIP 服务器的数据库中都有保存 在认证的过程中 客户端将自己的信息 用户名 密码 url 等信息 做一些复杂的MD5 或者SHA256 SH
  • 超声波传感器(CH101&ch201) - Ⅱ

    文章目录 1 前言 2 目前官方发布的Horn有以下几种 3 超声波TOF传感器 VS 红外线传感器 4 开发评估套件 1 前言 上一篇简单的引入了CH101 CH201 这两种传感器 这种传感器使用的时候除了需要芯片外 还需要一个声学的
  • BMP085气压传感器驱动 &MS5611经验

    BMP085是新一代的小封装气压传感器 主要用于气压温度检测 在四轴飞行器上可以用作定高检测 该传感器属于IIC总线接口 依然沿用标准IIC驱动程序 使用该传感器需要注意的是我们不能直接读出转换好的二进制温度数据或者气压数据 必须先读出一整

随机推荐