2025-06-02:最小可整除数位乘积Ⅱ。用go语言,给定一个表示正整数的字符串 num 和一个整数 t。 定义:如果一个整数的每一位都不是 0,则称该整数为

2025-06-02:最小可整除数位乘积Ⅱ。用go语言,给定一个表示正整数的字符串 num 和一个整数 t。

定义:如果一个整数的每一位都不是 0,则称该整数为"无零数字"。

任务要求:找出一个字符串,表示一个整数,满足以下条件:

  1. 该整数大于或等于 num。

  2. 是一个无零数字。

  3. 该整数所有数位上的数字相乘得到的积可以被 t 整除。

若存在符合条件的整数,返回其字符串表示;若不存在,返回 "-1"。

2 <= num.length <= 2 * 100000。

num 只包含 '0', '9' 之间的数字。

num 不包含前导 0 。

1 <= t <= 100000000000000。

输入:num = "1234", t = 256。

输出:"1488"。

解释:

大于等于 1234 且能被 256 整除的最小无零整数是 1488 ,它的数位乘积为 256 。

题目来自力扣3348。

解决步骤

  1. 检查 t 的质因子:

    • 首先,检查 t 是否包含大于 7 的质因子。因为数字的每一位只能是 1-9,所以乘积的质因子只能是 2、3、5、7。如果 t 包含其他质因子(如 11、13 等),则直接返回 "-1"。
    • 这一步通过将 t 不断除以 9 到 2 的数字,如果最终剩余的值大于 1,说明有大于 7 的质因子。
  2. 检查 num 是否已经满足条件:

    • 计算 num 的数字乘积是否能被 t 整除。如果能,直接返回 num。
    • 这里通过从左到右遍历 num 的每一位,逐步计算 t 的剩余部分(leftT)。如果遍历完 num 后 leftT 变为 1,说明 num 的数字乘积已经是 t 的倍数。
  3. 尝试构造和 num 长度相同的数字:

    • 从 num 的最高位开始,尝试找到一个比 num 大的数字,其数字乘积能被 t 整除。
    • 具体方法:
      • 从右到左找到第一个可以增加的位(即该位的数字可以增加 1 而不超过 9)。
      • 对于每个可能的增加位,尝试构造剩余的数字,使得整个数字的数字乘积能被 t 整除。
      • 构造剩余数字时,从大到小(9 到 1)选择数字,尽可能多地分解 t 的剩余部分。
  4. 构造比 num 更长的数字:

    • 如果无法找到和 num 长度相同的数字,则构造一个比 num 长的最小数字。
    • 将 t 分解为 9 到 2 的数字的乘积,然后按从小到大的顺序排列这些数字(因为我们需要最小的数字)。
    • 如果分解后的数字位数不足,补 1(因为 1 不影响乘积)。

时间复杂度和空间复杂度

  • 时间复杂度 :
    • 检查 t 的质因子:O(1),因为最多除以 9 到 2 的数字。
    • 遍历 num 计算 leftT:O(n),其中 n 是 num 的长度。
    • 尝试构造相同长度的数字:最坏情况下需要遍历 num 的每一位,并对每一位尝试 9 种可能,因此是 O(n * 9 * n) = O(n^2)。
    • 构造更长数字:O(log t),因为需要分解 t 为数字的乘积。
    • 总体时间复杂度:O(n^2 + log t)。对于大 n(如 2e5),这可能会很慢。
  • 空间复杂度 :
    • 存储 leftT 数组:O(n)。
    • 构造结果字符串:O(n) 或 O(log t)。
    • 总体空间复杂度:O(n)。

Go完整代码如下:

go 复制代码
package main

import (
	"fmt"
	"slices"
)

func smallestNumber(num string, t int64) string {
	tmp := int(t)
	for i := 9; i > 1; i-- {
		for tmp%i == 0 {
			tmp /= i
		}
	}
	if tmp > 1 { // t 包含大于 7 的质因子
		return "-1"
	}

	n := len(num)
	leftT := make([]int, n+1)
	leftT[0] = int(t)
	i0 := n - 1
	for i, c := range num {
		if c == '0' {
			i0 = i
			break
		}
		leftT[i+1] = leftT[i] / gcd(leftT[i], int(c-'0'))
	}
	if leftT[n] == 1 { // num 的数位之积已经是 t 的倍数
		return num
	}

	// 假设答案和 num 一样长
	s := []byte(num)
	for i := i0; i >= 0; i-- {
		for s[i]++; s[i] <= '9'; s[i]++ {
			tt := leftT[i] / gcd(leftT[i], int(s[i]-'0'))
			k := 9
			for j := n - 1; j > i; j-- {
				for tt%k > 0 {
					k--
				}
				tt /= k
				s[j] = '0' + byte(k)
			}
			if tt == 1 {
				return string(s)
			}
		}
	}

	// 答案一定比 num 长
	ans := []byte{}
	for i := int64(9); i > 1; i-- {
		for t%i == 0 {
			ans = append(ans, '0'+byte(i))
			t /= i
		}
	}
	for len(ans) <= n {
		ans = append(ans, '1')
	}
	slices.Reverse(ans)
	return string(ans)
}

func gcd(a, b int) int {
	for a != 0 {
		a, b = b%a, a
	}
	return b
}

func main() {
	num := "1234"
	t := int64(256)
	result := smallestNumber(num, t)
	fmt.Println(result)
}

Python完整代码如下:

.

python 复制代码
# -*-coding:utf-8-*-

from math import gcd

def smallest_number(num: str, t: int) -> str:
    tmp = t
    for i in range(9, 1, -1):
        while tmp % i == 0:
            tmp //= i
    if tmp > 1:  # t 包含大于 7 的质因子
        return "-1"

    n = len(num)
    leftT = [t] + [0] * n
    i0 = n - 1
    for i, c in enumerate(num):
        if c == '0':
            i0 = i
            break
        digit = int(c)
        leftT[i + 1] = leftT[i] // gcd(leftT[i], digit)
    if leftT[n] == 1:  # num 的数字乘积已经是 t 的倍数
        return num

    s = list(num)
    for i in range(i0, -1, -1):
        s[i] = chr(ord(s[i]) + 1)
        while s[i] <= '9':
            digit_i = int(s[i])
            tt = leftT[i] // gcd(leftT[i], digit_i)
            k = 9
            for j in range(n - 1, i, -1):
                while tt % k != 0:
                    k -= 1
                    if k <= 1:
                        break
                tt //= k
                s[j] = str(k)
            if tt == 1:
                return ''.join(s)
            s[i] = chr(ord(s[i]) + 1)

    # 答案长度一定比 num 长
    ans = []
    while t > 1:
        for i in range(9, 1, -1):
            while t % i == 0:
                ans.append(str(i))
                t //= i
    # 用 1 补足长度
    while len(ans) <= n:
        ans.append('1')
    ans.reverse()
    return ''.join(ans)

if __name__ == "__main__":
    num = "1234"
    t = 256
    result = smallest_number(num, t)
    print(result)
相关推荐
IT_陈寒14 小时前
Java线程池这破玩意,差点让我周末加班排查到凌晨
前端·人工智能·后端
弈栈录14 小时前
Java AI 应用的异步化与高并发设计
java·后端·架构
凤山老林15 小时前
Spring Boot 集成 iText 7 实现动态 PDF 生成与电子签章:合同、报表场景实战
spring boot·后端·pdf·itext7·电子签章
孙启超15 小时前
【AI开发之Rust】第 19 课:UniFFI 导出核心能力
开发语言·后端·rust
ServBay15 小时前
基于Jev的浏览器Agent插件狂揽 21k star,3分钟教你解放双手
后端·aigc·ai编程
Json____15 小时前
家居装修 AI 智能咨询助手:让装修咨询从“大海捞针“变成“一问即答“
java·后端·vue3·it学习·wwwoop.com
Apifox16 小时前
Apifox 9 月更新|CLI 能力升级、GitLab 私有化部署接入与产品体验优化
前端·后端·测试
鱼弦16 小时前
Agent智能体 vs 传统运维:职业天花板的3倍差距?
后端
暗夜行者之光16 小时前
LangGraph 实战:用 LangSmith 可视化追踪 AI 智能体执行轨迹
后端
鱼弦16 小时前
Agent 的工具选择策略:从硬编码到动态决策
后端