【跟着英雄学算法第⑫讲】因子和——附Leercode刷题题解(C语言实现)三种解法

✨前言✨

       在这个系列中,博主准备分享每日在万人千题社区打卡学习的算法。博主也是小白,因此也很能理解新手在刷题时的困惑,所以关注博主,每天学习一道算法吧。同时也欢迎大家加入万人千题习活动,正所谓:一个人可以走的很快,但一群人才能走的更远。

万人千题社区https://bbs.csdn.net/forums/hero?category=0icon-default.png?t=L9C2https://bbs.csdn.net/forums/hero?category=0


目录

一、素数知识回顾

二、算法思想笔记

三、1390.四因数

 ①题目呈现

 ②代码操练1

 ③代码操练2

​ ④代码操练3 


 

一、素数知识回顾

①素数判定:枚举 i * i <= num的所有情况

②算数基本定理:每一个整数都可以唯一分解成几个素数的乘积

③素数筛选与分解:枚举法,埃氏筛,欧拉筛……

④因子数:

 二、算法思想笔记

以n=2*2*2*3*3来说明:(2^0 + 2^1 +2^2 +2^3)* (3^0 + 3^+ 3^2)

每当确定一个2的取法,3的取法都是相同的,都有以上三种。因此根据乘法分配律可以结合成上述形式。

三、1390.四因数

四因数icon-default.png?t=L9C2https://leetcode-cn.com/problems/four-divisors/submissions/

①题目呈现

 ②代码操练1(英雄的解法,唯一与本专题相关)🙃

#define maxn 100001
#define ll long long

bool f[maxn];
int primes[maxn];//prime[0]相当于计数器的作用

void ethPrime(){
    int i;
    ll j;                                       
    f[0] = f[1] = 1;
    primes[0] = 0;
    for(i = 2; i < maxn; ++i) {
        if(!f[i]) {
            primes[++primes[0]] = i;
            for(j = (ll)i * i; j < maxn; j += i) {
                f[j] = 1;
            }
        }
    }
}

bool isPrime(int x) {
    return !f[x];
}

int sumFourDivisors(int* nums, int numsSize){
    int i, j, p, q;
    int ans = 0;
    ethPrime();                                  // (1)
    for(i = 0; i < numsSize; ++i) {              // (2)
        for(j = 1; j <= primes[0]; ++j) {        // (3)
            p = primes[j];
            if(nums[i] % p == 0) {
                q = nums[i] / p;
                if( isPrime(q) && p != q) {
                    ans += (p+1)*(q+1);         // (4)
                }
                if( q == (long long)p * p ) {
                    ans += p*p*p + p*p + p + 1; // (5)
                }                
                break;
            }
        }
    }
    return ans;
}

分析: 

1.根据之前所学的因子数知识和算数基本定理,我们得出有四个因子只有两种情况

1)两个素数的乘积         2)一个素数的三次方

2.ethPrime()函数用埃氏筛标记处于2~maxn之间所有的质数,便于我们之后求解

3.ans计算和判断原因见下图

 

结果: 

 

 ③代码操练2

int sumFourDivisors(int* nums, int numsSize)
{
    int total = 0;
    int j = 0;
    int i = 0;
    for( i = 0; i < numsSize ; i++)
    {
        int cnt = 0;
        int sum = 0;

        for( j = 1; j*j < nums[i]; j++)
        {
            if(nums[i] % j == 0)
            {
                cnt++;
                sum += j + nums[i] / j;
            }

        }
        if(cnt == 2 && j * j != nums[i])
        {
            total += sum;
        }
    }
    return total;

}

分析: 

 枚举法yyds,就不用我多说了吧。

结果: 

 ④代码操练3 

#define maxn 100005

bool f[maxn]={0};//标记对应下标数是否为变量
int prime[maxn]={0};

void prime_list()
{
    f[1] = 1;
    prime[0]=0;
    for (int i = 2; i <= 1E5; i++)//欧拉筛
    {
        if (!f[i])
        {
            prime[++prime[0]] = i;
        }
        for (int j = 1; i * prime[j] <= 1E5; j++)
        {
            f[i * prime[j]] = 1;
            if( i % prime[j] == 0)
                break;  
        }
    }
}

int sumFourDivisors(int* nums, int numsSize)
{
    prime_list();
    int total = 0;
    for (int i = 0; i < numsSize; i++)
    {
        int cnt = 0;
        for (int j = 1; prime[j]*prime[j] < nums[i] ; j++)
        {
            if (nums[i] % prime[j] == 0 && !f[nums[i] / prime[j]])
            {
                total += nums[i] + 1 + prime[j] + nums[i] / prime[j];
                break;
            }
            else if (nums[i] % prime[j] == 0 && pow(prime[j], 3) == nums[i])
            {
                total += 1 + prime[j] + prime[j] * prime[j] + prime[j]*prime[j]*prime[j];
                break;
            }
            
        }
    }
    return total;
}

分析:

解释一下内循环j的判断理由:

如果prime[j] 是nums[i]的质数,因为题目要求是四质数,则nums[i]/prime[j]必定为质数,否则合数可以再分成质数,结果就不会是四质数。

结果:

上面的代码希望对你有所帮助。有优化建议希望可以在下方留言

  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 16
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罅隙`

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值