个位数字为 K 的整数之和

237 阅读2分钟

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

说在前面

🎈每天进行一道算法题目练习,今天的题目是“个位数字为 K 的整数之和”。

问题描述

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

  • 每个整数个位数字都是 k 。
  • 所有整数之和是 num 。

返回该多重集的最小大小,如果不存在这样的多重集,返回 -1 。

注意:

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

 

示例 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 。

 

提示:

  • 0 <= num <= 3000
  • 0 <= k <= 9

思路分析

首先我们应该要先理解一下题意,题目给出两个参数,分别是:

  • k:我们可以使用的数 -> [0,3000]中个位数为k的数

  • num:我们需要使用[0,3000]中个位数为k的数组成的和 提取提示给出的信息:

  • 还有要注意的一点是:数字可以重复使用

  • 再看一下num的取值范围:0 <= num <= 3000 数据范围是0 <= num <= 3000,所以我们可以使用动态规划,求出0-3000中每一个数字可以组成的最少个数:
    我们可以总结出公式,dp[num] = dp[i] + dp[num - i] ---> dp[i] = dp[j] + dp[i - j],可以推出所有可能组成的数值需要使用数字的个数,具体步骤如下:

  • 1、统计个位数为k及其倍数的次数

let i = k;
let dp = new Array(num + 5).fill(0);
while(i <= num){
   if(i == 0) i += 10;
   if(i == num) return 1;
   for(let j = 1; j * i <= num; j++){
       dp[j * i] = j;
   }
   i += 10;
}
  • 2、求组成所求的值得最小个数
if(dp[num]) res = dp[num];
for(let i = 0; i <= num; i++){
   if(dp[i] && dp[num - i]) res = Math.min(dp[i] + dp[num - i],res);
}

AC代码

/**
 * @param {number} num
 * @param {number} k
 * @return {number}
 */
 var minimumNumbers = function(num, k) {
    if(num == 0) return 0;
   let i = k;
   let res = Infinity;
   let dp = new Array(num + 5).fill(0);
   dp[0] = 0;
   while(i <= num){
       if(i == 0) i += 10;
       if(i == num) return 1;
       for(let j = 1; j * i <= num; j++){
           dp[j * i] = j;
       }
       i += 10;
   }
   if(dp[num]) res = dp[num];
   for(let i = 0; i <= num; i++){
       if(dp[i] && dp[num - i]) res = Math.min(dp[i] + dp[num - i],res);
   }
   return res == Infinity ? -1 : res;
};

说在后面

🎉这里是JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打打羽毛球🏸 ,平时也喜欢写些东西,既为自己记录📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解🙇,写错的地方望指出,定会认真改进😊,在此谢谢大家的支持,我们下文再见🙌。