【C/C++】2310. 个位数字为 K 的整数之和

231 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第36天,点击查看活动详情


题目链接:2310. 个位数字为 K 的整数之和

题目描述

给你两个整数 numk ,考虑具有以下属性的正整数多重集:

每个整数个位数字都是 k

  • 所有整数之和是 num
  • 返回该多重集的最小大小,如果不存在这样的多重集,返回 -1

注意:

  • 多重集与集合类似,但多重集可以包含多个同一整数,空多重集的和为 0
  • 个位数字 是数字最右边的数位。

提示:

  • 0num30000 \leqslant num \leqslant 3000
  • 0k90 \leqslant k \leqslant 9

示例 1:

输入:num = 58, k = 9
输出:2
解释:
多重集 [9,49] 满足题目条件,和为 58 且每个整数的个位数字是 9 。
另一个满足条件的多重集是 [19,39] 。
可以证明 2 是满足题目条件的多重集的最小长度。

示例 2:

输入: num = 37, k = 2
输出: -1
解释: 个位数字为 2 的整数无法相加得到 37 。

示例 3:

输入: num = 0, k = 7
输出: 0
解释: 空多重集的和为 0 。

整理题意

题目给定两个整数 numk,求最少可以使用多少个位数字为 k 的整数凑成 num

题目规定:

  • 如果无法凑成 num 返回 -1
  • 最少使用整数的个数为 0,也就是当 num0 时,返回 0
  • 可以重复使用同一个整数。

解题思路分析

首先观察题目数据范围,num3000 以内,数据范围较小,可以采用较为暴力的方式来解题。

观察题目特点,使用整数的个位数字都为 k,那么我们可以把 num 拆分为两个部分:num = n * k + 10 * m

  1. n * k:表示总共使用 n 个数,且每个整数的个位数字都为 k,那么总和的一部分就为 n * k
  2. 10 * m:除开个位数字,剩下的就是十位数及以上的数字,所以可以表示为 10 * m,这里的 m 为非负整数。也就是去掉 n * k 这部分后,剩下的数字一定是 10 的倍数,因为个位数已经确定。 根据 num = n * k + 10 * m 这个式子,因为已知 numk,我们需要求最小的 n,那么可以通过从小到大枚举 n 来判断 num - n * k 是否为 10 的倍数,因为这里的 m 只需要为非负整数即可。

其次我们需要考虑 n 枚举的范围:

  1. n0 时表示多重集和为空,根据题目规定此时返回 0,此时对应 num0 的情况,我们特判该情况即可。
  2. 考虑枚举 n 的下界为 1,因为至少需要一个整数凑成 num
  3. 考虑枚举 n 的上界为多少(难点),此时考虑最差的情况,k = 1 的时候我们凑成 num 的最坏情况需要 num1,所以枚举上界为 num(再观察 num 的数据范围再 3000 以内,确保不会超时)。

优化

我们可以发现当枚举的 n 超过 10 时,比如 n = 11 时,可以将 11 * k 继续拆分为 k + 10 * k,此时 10 * k10 的倍数,可以将其放进 10 * m 中,从而 n 又回到了 1,此时可以使得选择的数仍然满足要求,并且 n 更小。

所以 n 枚举的上界可以优化为 10

需要注意的是枚举上界包括 10

具体实现

  1. 首先特判 num = 0 的情况,返回 0
  2. [1, 10] 中从小到大枚举答案 n,返回最小的能够使得 (num - n * k)10 的倍数的 n

需要注意 num - n * k 需要为非负整数,也就是 num - n * k >= 0

  1. 如果在 [1, 10] 中无法找到满足条件的 n,也就是不存在这样的多重集,此时返回 -1

复杂度分析

  • 时间复杂度:O(1)O(1),最多遍历 10 次,仅需常数时间。
  • 空间复杂度:O(1)O(1),仅需常数存储空间。

代码实现

class Solution {
public:
    int minimumNumbers(int num, int k) {
        //特判num为0时空多重集
        if(num == 0) return 0;
        //[1, 10]枚举答案
        for(int i = 1; i <= 10 && i * k <= num; i++){
            if((num - i * k) % 10 == 0) return i;
        }
        //不存在这样的多重集
        return -1;
    }
};

总结

  • 该题通过观察其特点,分析出组成 num 的两个部分 num = n * k + 10 * m 是解题关键。
  • 其次考虑使用 枚举 的方法来搜索答案,同时需要考虑枚举的上下界,以及边界情况是否需要特判。
  • 最后考虑枚举范围是否可以优化。
  • 测试结果:

2310.png

结束语

人生有自己定义,不必为迎合别人而焦虑;人生无法重来,不必因害怕失去而徘徊。心态好的人,不是不会遇到困难,而是懂得把发生的事情当成垫脚石,不断向下扎根、向上成长。愿你用好的心态,过出独一无二的生活。新的一天,加油!