Leetcode 第 143 场双周赛题解

Leetcode 第 143 场双周赛题解

题目1:3345. 最小可整除数位乘积 I

思路

至多循环 10 次,一定会遇到个位数为 0 的数字,数位乘积是 0,一定是 t 的倍数。

所以暴力枚举即可。

代码

/*
 * @lc app=leetcode.cn id=3345 lang=cpp
 *
 * [3345] 最小可整除数位乘积 I
 */

// @lc code=start
class Solution
{
public:
    int smallestNumber(int n, int t)
    {
        for (int i = n; i <= n + 10; i++)
            if (digitMultSum(i) % t == 0)
                return i;
        return -1;
    }
    // 辅函数 - 求数字 x 的各数位之积
    int digitMultSum(int x)
    {
        int res = 1;
        while (x)
        {
            res *= (x % 10);
            x /= 10;
        }
        return res;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(logn)。

空间复杂度:O(1)。

题目2:3346. 执行操作后元素的最高频率 I

思路

差分数组。

设 x=nums[i]。x 可以变成 [x−k,x+k] 中的整数。注意对于同一个 nums[i] 至多操作一次。

反过来想,对于一个整数 y,有多少个数可以变成 y?

这可以用差分计算,也就是把 [x−k,x+k] 中的每个整数的出现次数都加一。

计算差分的前缀和,就得到了有 sumD 个数可以变成 y。

如果 y 不在 nums 中,那么 y 的最大频率为 min(sumD,numOperations)。

如果 y 在 nums 中,且出现了 cnt 次,那么有 sumD−cnt 个其他元素(不等于 y 的数)可以变成 y,但这不能超过 numOperations,所以有 min(sumD−cnt,numOperations) 个其他元素可以变成 y,再加上 y 自身出现的次数 cnt,得到 y 的最大频率为 cnt+min(sumD−cnt,numOperations)=min(sumD,cnt+numOperations)。

代码

/*
 * @lc app=leetcode.cn id=3346 lang=cpp
 *
 * [3346] 执行操作后元素的最高频率 I
 */

// @lc code=start
class Solution
{
public:
    int maxFrequency(vector<int> &nums, int k, int numOperations)
    {
        unordered_map<int, int> cnt;
        map<int, int> diff;
        for (int x : nums)
        {
            cnt[x]++;
            diff[x];       // 把 x 插入 diff,以保证下面能遍历到 x
            diff[x - k]++; // 把 [x-k, x+k] 中的每个整数的出现次数都加一
            diff[x + k + 1]--;
        }

        int ans = 0, sum_d = 0;
        for (auto &[x, d] : diff)
        {
            sum_d += d;
            ans = max(ans, min(sum_d, cnt[x] + numOperations));
        }
        return ans;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(nlogn),其中 n 是数组 nums 的长度。

空间复杂度:O(n),其中 n 是数组 nums 的长度。

题目3:3347. 执行操作后元素的最高频率 II

同第二题。

题目4:3348. 最小可整除数位乘积 II

思路

题解:https://leetcode.cn/problems/smallest-divisible-digit-product-ii/solutions/2984014/bao-sou-zuo-fa-lei-si-shu-wei-dp-by-endl-nkoo/

代码

/*
 * @lc app=leetcode.cn id=3348 lang=cpp
 *
 * [3348] 最小可整除数位乘积 II
 */

// @lc code=start
class Solution
{
public:
    string smallestNumber(string s, long long t)
    {
        long long tmp = t;
        for (int i = 9; i > 1; i--)
        {
            while (tmp % i == 0)
            {
                tmp /= i;
            }
        }
        if (tmp > 1)
        { // t 包含大于 7 的质因子
            return "-1";
        }

        int n = s.length();
        vector<long long> left_t(n + 1);
        left_t[0] = t;
        int i0 = n - 1;
        for (int i = 0; i < n; i++)
        {
            if (s[i] == '0')
            {
                i0 = i;
                break;
            }
            left_t[i + 1] = left_t[i] / gcd(left_t[i], s[i] - '0');
        }
        if (left_t[n] == 1)
        { // s 的数位之积是 t 的倍数
            return s;
        }

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

        // 答案一定比 s 长
        string ans;
        for (int i = 9; i > 1; i--)
        {
            while (t % i == 0)
            {
                ans += '0' + i;
                t /= i;
            }
        }
        ans += string(max(n + 1 - (int)ans.length(), 0), '1');
        ranges::reverse(ans);
        return ans;
    }
};
// @lc code=end

复杂度分析

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值