【第31天】给定一个整数 n ,求出它的每个质因数的底数与指数 | 算术基本定理

本文已收录于专栏
《Java入门一百例》

学习指引

  • 序、专栏前言
  • 序、本章前言
  • 算术基本定理
  • 一、【例题1】
    • 1、题目描述
    • 2、解题思路
    • 3、模板代码
    • 4、代码解析
  • 三、推荐专栏
  • 四、课后习题

序、专栏前言

   本专栏开启,目的在于帮助大家更好的掌握学习Java,特别是一些Java学习者难以在网上找到系统地算法学习资料帮助自身入门算法,同时对于专栏内的内容有任何疑问都可在文章末尾添加我的微信给你进行一对一的讲解。
   但最最主要的还是需要独立思考,对于本专栏的所有内容,能够进行完全掌握,自己完完全全将代码写过一遍,对于算法入门肯定是没有问题的。
   算法的学习肯定不能缺少总结,这里我推荐大家可以到高校算法社区将学过的知识进行打卡,以此来进行巩固以及复习。
  学好算法的唯一途径那一定是题海战略,大量练习的堆积才能练就一身本领。专栏的任何题目我将会从【题目描述】【解题思路】【模板代码】【代码解析】等四板块进行讲解。

序、本章前言

  算术基本定理是一个非要重要的定理,它的存在是许多重要公式的基础,比如前两天我们学习的约数个数和约数之和算法。它都是建立在算术基本定理上,当时我们直接进行了质因数分解的,可能有的小伙伴还不太理解。今天我们系统来进行讲解一下

算术基本定理

  算术基本定理课表述为:任何一个大于 1 1 1自然数 N N N,如果 N N N不为质数,那么 N N N可以唯一分解成有限个数的乘积:
N = ∏ i = 1 k p i i = p 1 a 1 × p 2 a 2 × p 3 a 3 . . . . . . p k a k ( p 1 , p 2 . . . . p k 均 为 质 数 ) N=\prod_{i=1}^{k} p_i^{^i}=p_1^{a^1}\times p_2^{a^2}\times p_3^{a^3}......p_k^{a^k}(p_1,p_2....p_k均为质数) N=i=1kpii=p1a1×p2a2×p3a3......pkak(p1,p2....pk)
  其中指数 a i a_i ai均为正整数,这样的分解式称为 N N N的标准分解式。最早是由欧几里得证明给出。 算术基本定理的证明在此我们不细讲,拓展一些基于算术基本定理可以得到的一些证明。

  • ( 1 ) (1) (1)约数之和定理, N N N的所有正因数之和: f ( N ) = ( p 1 0 + p 1 1 + . . . + p 1 a 1 ) ∗ ( p 2 0 + p 2 1 + . . . + p 2 a 2 ) ∗ . . . ( p k 0 + p k 1 + . . . + p k a k ) f(N)=(p_1^0+p_1^1+...+p_1^{a_1})*(p_2^0+p_2^1+...+p_2^{a_2})*...(p_k^0+p_k^1+...+p_k^{a_k}) f(N)=(p10+p11+...+p1a1)(p20+p21+...+p2a2)...(pk0+pk1+...+pkak)
  • ( 2 ) (2) (2)对于两个整数 a a a b b b,有 a ∗ b a*b ab= g c d ( a , b ) ∗ l c m ( a , b ) gcd(a,b)*lcm(a,b) gcd(a,b)lcm(a,b)
  • ( 3 ) (3) (3)说明素数的个数是无限的。

一、【例题1】

1、题目描述

  给定 n ( 1 ≤ n ≤ 100 ) n(1 \le n \le 100) n(1n100)个正整数 a i ( 2 ≤ a i ≤ 2 ∗ 1 0 9 ) a_i(2 \le a_i \le2*10^9) ai(2ai2109),将每个数分解质因数,并按照质因数从小到大的顺序输出每个质因数的底数和指数。

2、解题思路

  • ( 1 ) (1) (1)由于需要分解多个数,所以我们将分解一个数的操作抽成一个函数进行操作
  • ( 2 ) (2) (2)注意 a i a_i ai的范围很大,我们使用long读取。

3、模板代码

import java.util.*;

public class a {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        for (int i = 0; i < n; i++) {
            long x=sc.nextLong();
            test(x);
        }
    }
    static void test(long x){
        for (int i = 2; i <=x;i++) {
            if (x%i==0){
                int ans=0;
                while (x%i==0){
                    x/=i;
                    ans++;
                }
                System.out.println(i+" "+ans);
            }
        }
    }
}

但很明显我们发现,设每个数的取值范围为 m m m,时间复杂达到了 O ( n m ) O(nm) O(nm),这是不可接收的,我们考虑对test函数进行优化

static void test(long x){
        for (int i = 2; i <=x/i;i++) {
            if (x%i==0){
                int ans=0;
                while (x%i==0){
                    x/=i;
                    ans++;
                }
                System.out.println(i+" "+ans);
            }
        }
        if (x>1) System.out.println(x+" "+1);
    }

4、代码解析

  • ( 1 ) (1) (1)很明显,对于 O ( m ) O(m) O(m)复杂度的test操作我们优化为 O ( n ) O(\sqrt n) O(n )。它基于的原理是对于一个正整数 n n n,它的质因数中大于 n \sqrt n n 的最多只能有一个。这也很好证明,假设有两个,那么相乘肯定大于 n n n了。
  • ( 2 ) (2) (2)所以对于每个数 x x x,我们不需要完全遍历,只需要遍历到 x \sqrt x x 的级别即可,最后判断 x x x是否大于 1 1 1,如果大于说明它此时就是那个大于 x \sqrt x x 的质因数。

三、推荐专栏

《零基础学算法100天》

四、课后习题

序号 题目链接 难度评级
1 丑数3 2
学习有疑问?

你可能感兴趣的:(《Java入门100练》,java,算法,leetcode,蓝桥杯)