力扣刷题第二天 统计整数数目(每天一题)

这篇具有很好参考价值的文章主要介绍了力扣刷题第二天 统计整数数目(每天一题)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

统计整数数目

给你两个数字字符串 num1 和 num2 ,以及两个整数 max_sum 和 min_sum 。如果一个整数 x 满足以下条件,我们称它是一个好整数:

  • num1 <= x <= num2
  • min_sum <= digit_sum(x) <= max_sum.

请你返回好整数的数目。答案可能很大,请返回答案对 109 + 7 取余后的结果。

注意,digit_sum(x) 表示 x 各位数字之和。

示例一

输入:num1 = "1", num2 = "12", min_num = 1, max_num = 8
输出:11
解释:总共有 11 个整数的数位和在 1 到 8 之间,分别是 1,2,3,4,5,6,7,8,10,11 和 12 。所以我们返回 11 。
  • 1 <= num1 <= num2 <= 1022
  • 1 <= min_sum <= max_sum <= 400
思路:

题目要求求解数值范围在 nums1到 nums2之间,并且数位和在 min_sum到 max_sum之间的整数个数,其中nums1和 nums2以字符串形式给出。

定义函数 get(num),用于求解 1∼num1范围内有多少整数数位和介于 min_sum∼max_sum之间,那么原问题就转换为求解 get(num2)−get(num1−1)

设 num 共有n 位,我们从最高位(即第 n−1 位)开始遍历,目前聚焦于第 i 位,前面第 n−1 位到第 i+1 位的数位和为 sum,现在需要考虑第 i 位填充的数字 x。通常 x 可以取 0∼9 中的任意一个数字,但当第 n−1 位到第 i+1 位放置的数字都与 num 一样时,x 的取值范围缩小至 0∼num[i],在代码中,当 limit 为 true 时,表示这一特殊情况发生。

试想,如果 limit 标识为false,x 取值范围为 0∼9,那么后续的第 i−1 到第 0 位的取值范围都是 0∼9。这样一来,子问题就与 num 的值无关。我们定义状态 d[i][j] 表示还剩第 i 位到第 0 位的数字未填,而已填的数字位数之和为 j 时,符合条件的数字个数有多少个。在求解时,子问题与 n 的值无关,也与 num 无关,因此只有当limit 为 false 可以使用或更新 d[i][j]。

当然,limit 这一维度也可以加入到状态中,但 limit 为 true 的子问题只会被调用一次,将答案记忆化存储毫无意义,并且每次重新调用 get 时都需要重新计算所有状态答案,得不偿失。因此定义函数 dfs(i,j,limit) 用于问题求解,在 limit 为 false 时借助 d[i][j] 防止重复计算,加快执行速度。

 细节:

我们采用记忆化搜索的方式实现数位动态规划,将所有d[i][j] 的初始值设置为 −1。递归过程:

  若 limit 为 true 时,在 0∼num[i] 范围内遍历 x,并递归调用 dfs(i−1,j+x,limit&&x==nums[i]),统计所有返回值的和作为答案。
  若 limit 为 false 时,若 d[i][j] != −1,则直接返回 d[i][j],否则在 0∼9 范围内遍历 x,并递归调用 dfs(i−1,j+x,false),统计所有返回值的和并更新 d[i][j]。
若 j 已经大于 max_sum,可以剪枝,直接返回 0。当 i 等于 −1 时,递归结束,此时若 j≥min_sum 则返回 1,否则返回 0。

  需要注意的是,由于上文中第 n−1 位表示数字的最高位,第 0 位表示数字的最低位(即个位),因此需要将题目中输入的数字翻转。

  另外在计算最终结果时一定记得num2和num1-1的结果相减后,加上一个模后再取一次模,因为取模前提下后者不一定小于前者,最终答案肯定不能是负数。文章来源地址https://www.toymoban.com/news/detail-794528.html

class Solution {

        static constexpr int N = 23;
        static constexpr int M = 401;
        static constexpr int MOD = 1e9 + 7;
        int d[N][M];
        string num;
        int min_sum;
        int max_sum;

        int dfs(int i,int j,bool limit)
        {
            if(j>max_sum)
            {
                return 0;
            }
            if(i == -1)
            {
                return j >=min_sum;//当 i 等于−1时,递归结束,此时若 j≥min_sum则返回 1,否则返回0
            }
            if(!limit && d[i][j] != -1)
            {
                return d[i][j];
            }
            int res = 0;
            int up = limit ? num[i] - '0' : 9;
            for (int x = 0; x <= up; x++)
            {
                res = (res + dfs(i - 1, j + x, limit && x==up)) % MOD;
            }
            if(!limit)
            {
                d[i][j] = res;
            }
            return res;
        }

        int get(string num)
        {
            reverse(num.begin(),num.end());// 反转字符串
            this->num = num;// 将反转后的字符串保存到成员变量中
            return dfs(num.size() - 1, 0 ,true);// 调用dfs函数进行递归计算
        }

        //求解 num - 1,先把最后一个非 0 字符减去 1,再把后面的 0 字符变为 9
        string sub(string num)
        {
            int i = num.size() - 1;
            while(num[i] == '0')
            {
                i--;
            }
            num[i]--;
            i++;
            while(i < num.size())
            {
                num[i] = '9';
                i++;
            }
            return num;
        }
      
    public:
    int count(string num1, string num2, int min_sum, int max_sum) {
        memset(d,-1,sizeof d);
        this->min_sum = min_sum;
        this->max_sum = max_sum;
        return (get(num2) - get((sub(num1))) + MOD) % MOD;//一定记得num2和num1-1的结果相减后,加上一个模后再取一次模,因为取模前提下后者不一定小于前者,最终答案肯定不能是负数。
    }
};

到了这里,关于力扣刷题第二天 统计整数数目(每天一题)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 力扣刷题笔记-07 整数反转

    狗看了都摇头的年纪,纯爱战士一败涂地。 temp用来保存个位数 res用来保存当前结果 123,取模运算,这样就可以获得最后一位。比如对123%10,得到temp=3. 判断res是不是溢出( 重点 ) 如果没有溢出,res扩大十倍,再加上个位数,就相当于是反转了。res = res * 10 + temp; 返回res。

    2024年02月08日
    浏览(32)
  • 「数位dp」统计整数数目(力扣第2719题)

    本题为1月16日力扣每日一题 题目来源:力扣第2719题 题目tag: 数位dp 动态规划 给你两个数字字符串num1和num2,以及两个整数max_sum和min_sum。如果一个整数x满足以下条件,我们称它是一个好整数: (num1 leq x leq num2) (min_sum leq digit_sum(x) leq max_sum) 请你返回好整数的数目。答案

    2024年01月16日
    浏览(32)
  • 力扣刷题笔记-08 字符串转整数

    属于对字符串进行操作的问题 百无一用是情深 字符串里有数字,空格,正负号等,需要先过滤出来 在这道题目里,我们通常考虑字符串的组合是 “空格+正负号+数字”,一开始我想可能是“正负号+空格+数字”,但是这样的组合根本不可能是数字啊,没什么意义。 for循环

    2024年02月08日
    浏览(29)
  • leetcode2719. 统计整数数目

    Problem: 2719. 统计整数数目 给你两个数字字符串 num1 和 num2 ,以及两个整数 max_sum 和 min_sum 。如果一个整数 x 满足以下条件,我们称它是一个好整数: num1 = x = num2 min_sum = digit_sum(x) = max_sum. 请你返回好整数的数目。答案可能很大,请返回答案对 109 + 7 取余后的结果。 注意,d

    2024年01月18日
    浏览(39)
  • 刷题第四十二天 123. 买卖股票的最佳时机Ⅲ 188. 买卖股票的最佳时机Ⅳ

    和前一题的限制在于只能买卖两次,所以dp数组多定义一个状态,分别表示第一次持有 第一次不持有和第二次持有 第二次不持有,然后进行更新。 注意初始化的时候 第一次持有和第二次持有都需要默认0-prices[0] 和前一题的差别就是可以多次买卖,所以定义一个三维数组,表

    2024年02月05日
    浏览(36)
  • [leetcode~数位动态规划] 2719. 统计整数数目 hard

    给你两个数字字符串 num1 和 num2 ,以及两个整数 max_sum 和 min_sum 。如果一个整数 x 满足以下条件,我们称它是一个好整数: num1 = x = num2 min_sum = digit_sum(x) = max_sum. 请你返回好整数的数目。答案可能很大,请返回答案对 109 + 7 取余后的结果。 注意,digit_sum(x) 表示 x 各位数字之

    2024年01月18日
    浏览(32)
  • LeetCode 2719. 统计整数数目,数位dp板子题

    1、题目描述 给你两个数字字符串  num1  和  num2  ,以及两个整数  max_sum  和  min_sum  。如果一个整数  x  满足以下条件,我们称它是一个好整数: num1 = x = num2 min_sum = digit_sum(x) = max_sum . 请你返回好整数的数目。答案可能很大,请返回答案对  109 + 7  取余后的结果。 注意

    2024年01月17日
    浏览(35)
  • 【力扣刷题 | 第十六题】

    目录 前言: 198. 打家劫舍 - 力扣(LeetCode) 213. 打家劫舍 II - 力扣(LeetCode)  总结: 我们今天继续刷动态规划的题,希望大家可以和我一起坚持下去。 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有

    2024年02月15日
    浏览(31)
  • 【力扣刷题 | 第七天】

    今天我们将会进入栈与队列的刷题篇章,二者都是经典的数据结构,熟练的掌握栈与队列实现可以巧妙的解决有些问题。 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty): 实现 MyQueue 类: void push(int x) 将元素 x 推到队列的

    2024年02月09日
    浏览(37)
  • 力扣刷题笔记

    诸神缄默不语-个人CSDN博文目录 我以前刷过一波力扣,然后全忘了……从0开始的力扣复活赛! 以前刷题用的是Java,现在Java几乎忘光了,所以现在是Python 3 + Java双语选手。 以下题目按照力扣官方顺序排列。 449. 序列化和反序列化二叉搜索树 1281. 整数的各位积和之差 1749. 任意

    2024年02月14日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包