LeetCode 1922. 统计好数字的数目----快速幂的几种实现方式

题目

我们称一个数字字符串是“好数字”当它满足(下标从 0 开始)偶数下标处的数字为偶数且奇数下标处的数字为质数(2,3,5 或 7)。

比方说,“2582” 是好数字,因为偶数下标处的数字(2 和 8)是偶数且奇数下标处的数字(5 和 2)为质数。但 “3245” 不是好数字,因为 3 在偶数下标处但不是偶数。
给你一个整数 n ,请你返回长度为 n 且为好数字的数字字符串总数 。由于答案可能会很大,请你将它对 10^9 + 7取余后返回 。

一个数字字符串是每一位都由 0 到 9 组成的字符串,且可能包含前导 0 。

示例 1:

输入:n = 1
输出:5
解释:长度为 1 的好数字包括 "0","2","4","6","8" 。
示例 2:

输入:n = 4
输出:400
示例 3:

输入:n = 50
输出:564908303
 

提示:

1 <= n <= 10^15

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-good-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

由题目可轻松得出。当数字下标为奇数时,有2,3,5,7四种可能。当下标为偶数时,有0,2,4,6,8五种可能。且题目允许包含前导0。我们只需求出所有排列组合

一、暴力破解
class Solution {
    public int countGoodNumbers(long n) {
        long ans=1;
        for (long i=0;i<n;i++){
            if (i%2==0){
                ans*=5;
            }else {
                ans*=4;
            }
            ans%=(1_000_000_000+7);
        }
        return (int)ans;
    }
}

由于数字的位数为n,我们可以用一个for循环解决问题。但是,需要注意题目n的范围。毫无疑问,当n=10^15,肯定会超时。这时我们可以换一种算法,通过递归求出结果。

二、递归
class Solution {
    public int countGoodNumbers(long n) {
        //x为乘4个数,y为乘5个数
        long x=n/2;
        long y=n-x;

        x = pow(4l, x);
        y = pow(5l,y);
        return (int) ((x * y) % (1_000_000_000 + 7));
    }
    long pow(long x,long n){
        if(n==0)
            return 1;
        if(n==1)
            return x;
        long num=pow(x,n/2);
        if (n%2==0){
            return (num*num)% (1_000_000_000 + 7);
        }else {
            return (num*num*x)% (1_000_000_000 + 7);
        }
    }
}

在这里插入图片描述
由代码可以看出,递归的时间复杂度为O(log2(n))。除了上面这种写法外,我们也可以使用栈来实现递归

三、栈实现快速幂
class Solution {
    public int countGoodNumbers(long n) {
        //x为乘4个数,y为乘5个数
        long x=n/2;
        long y=n-x;

        x = pow(4l, x);
        y = pow(5l,y);
        return (int) ((x * y) % (1_000_000_000 + 7));
    }
    long pow(long x,long n){
        LinkedList<Long> stack=new LinkedList<>();
        while (n!=0){
            stack.push(n % 2 == 0?1l:x);
            n/=2;
        }
        long ans=1l;
        while (!stack.isEmpty()){
            ans*=ans*stack.pop();

            ans%=(1_000_000_000+7);
        }
        return ans;
    }
}
四、位运算实现快速幂
class Solution {
    public int countGoodNumbers(long n) {
        //x为乘4个数,y为乘5个数
        long x=n/2;
        long y=n-x;

        x = pow(4l, x);
        y = pow(5l,y);
        return (int) ((x * y) % (1_000_000_000 + 7));
    }
    long pow(long x,long n){
        long ans=1;
        while (n!=0){
            if ((n&1)==1){
                ans=ans*x;
            }
            x*=x;
            x%=1_000_000_000+7;
            ans%=1_000_000_000+7;
            n>>=1;
        }
        return ans;
    }
}

此方法为快速幂实现模板,通过位移实现对x求幂。

总结

以上就是常用的几种快速幂算法,若上诉有错误或者能够改进的地方,欢迎大家指出纠正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值