✨前言✨
在这个系列中,博主准备分享每日在万人千题社区打卡学习的算法。博主也是小白,因此也很能理解新手在刷题时的困惑,所以关注博主,每天学习一道算法吧。同时也欢迎大家加入万人千题习活动,正所谓:一个人可以走的很快,但一群人才能走的更远。
万人千题社区https://bbs.csdn.net/forums/hero?category=0https://bbs.csdn.net/forums/hero?category=0
目录
一、素数知识回顾
①素数判定:枚举 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.四因数
四因数https://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]必定为质数,否则合数可以再分成质数,结果就不会是四质数。
结果:
上面的代码希望对你有所帮助。有优化建议希望可以在下方留言