萌新刷算法题笔记1

前言:算法小白,无任何编程项目经历,最近入坑leetcode,分享下自己刷题的经验与感悟。我自认为编程能力中等偏下,刚开始刷中等以上题基本上不会,有时候想一个小时也没有好思路,可能自身资质不行。这里就先列举一道我认为比较经典的数学题目,我尽量用最通俗易懂的语言解释。(持续更新)

1~n整数中1出现的次数

题目介绍:输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
输入限制:1 <= n < 231

问题分析

一般 leetcode 上题对时间复杂度要求较高,一般10^5 左右大小的数组遍历,就不能用O(N2) 来写,否则会超时。一般 109 左右大小,基本上O(N) 也 gg。这个题显然是个数学问题,我们得想办法借用公式来判断,然后让其复杂度为O(logN)。
我刚开始分析也没啥头绪,随便找了几个数试了下,然后发现了点规律,PS:这种题一定多动手。
比如27,1-9有1个1,10-19的十位数有10个1,个位数有一个1,20-27有1个1,总个数就是13。
我们再抽象一下,比如78,相当于1-9是一部分,10-19 是一部分,值固定为10+1,然后20-69是一部分,值相当于5倍的0-9,70-78是一部分,值相当于1-8中的1。
这个时候,我发现,如果10-19,比如说17,就不能用这个拆分方式了,值固定不了。我用117举例,1-99为一部分,然后117-100 = 17,100-117的百位有17+1个1,十个位00-17与1-17的1相同,一加起来就48个。

思路形成

这么分析一波,貌似这题就很easy了,有手就行。上述过程大家看懂的话,那接下来就轻松愉快了,整理一下,分2种情况(首位1开头,非1开头),2个公式。
1开头:把n的位数搞出来,比如k,那么先求 10k -1中1的个数,加上最高位的1:n - 10k + 1,加上剩余位的1:n - 10k 中1的个数。
非1开头:先求 10k -1中1的个数,然后加上10k ,加上(n % 10k -1) 倍的 n - 10k 中的1的个数,最后加上剩余的n % 10k 中的1的个数。

萌新代码(供参考)

java版本,但是基本任何语言都可以看懂。

public int countDigitOne(int n) {
        return fun(n);
    }
    
    public int fun(int x){
        if(x == 0)
            return 0;
        if(x > 0 && x <= 9)
            return 1;
        String s = String.valueOf(x);
        int p = (int)Math.pow(10, s.length()-1);
        int h = s.charAt(0) - '0';
        int l = x - p*h;
        if(h == 1)
            return fun(p-1) + l+1 + fun(l);
        else
            return fun(l) + h * fun(p-1) + p;
    }

总结

感谢各位花时间看我的文章,其实我刷题基本不看题解的,因为我觉得,想不出来思路,即使把别人思路背下来,过段时间几瓶酒下去就会忘光,还是白扯。所以刷算法题要多思考,实在不会了,看别人题解,想想为什么要这样,为什么你想不想出来,弥补自己的不足。希望各位看过我文章的朋友都能快速上算法车。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值