备战蓝桥算法学习之每日练习题

2024.3.1算法学习

题目1:输入一个数N,用简单素数筛选法求N以内的素数。

在做题之前,先了解什么是素数:

质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数(规定1既不是质数也不是合数)。

再来写代码:

package lanqiao_study;

import java.util.Scanner;

public class 素数 {

	public static void main(String[] args) {
		/*
		 * 题目:输入一个数,用简单素数筛选法求N以内的素数。
		 */
		//1.输入一个数
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		boolean isFlag = false;
		//2.寻找n以内的素数
		for(int i = 2;i <= n;i++) {
			//素数:也称为质数,质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
			//所以,1不是质数,不用判断
			isFlag = true;
			for(int j = 2;j <= Math.sqrt(i);j++) {
				if(i % j == 0) {
					isFlag = false;
					break;
				}
			}
			if(isFlag){
				System.out.println(i);
			}
		}
	}

}

现在,对该程序进行时间复杂度分析:

1.找核心代码,这段程序的核心代码为两个for循环,所以只看for循环即可
2.for(int i = 2;i <= n;i++) {
			isFlag = true;//执行2~n次
			for(int j = 2;j <= Math.sqrt(i);j++) {//执行2~sqrt(i)次
				if(i % j == 0) {//执行1次
					isFlag = false;//执行1次
					break;//执行1次
				}
			}
			if(isFlag){//执行2~n次
				System.out.println(i);//执行1次
			}
		}
3.将执行1次的代码去除,只保留花费时间多的代码
for(int i = 2;i <= n;i++) {//执行2~n次
	for(int j = 2;j <= Math.sqrt(i);j++) {//执行2~sqrt(i)次
	//执行代码……
	}
}

在这段代码中,外层循环执行了n-1次(从i=2到i=n),而内层循环的执行次数取决于i的值。

内层循环的最大执行次数是 i \sqrt{i} i 次。因此,总的执行次数是:2+3+4+……+ n \sqrt{n} n

这个求和的上限是 n \sqrt{n} n 。这是一个等差数列的求和,根据等差数列公式:

2+3+4+……+k= k ( k + 1 ) 2 − 1 {k(k+1)\over2}-1 2k(k+1)1

将k替换为 n \sqrt{n} n ,得到:

2+3+4+……+ n \sqrt{n} n = n ∗ ( n + 1 ) 2 − 1 {\sqrt{n}*(\sqrt{n}+1)\over2}-1 2n (n +1)1

因此,总的时间复杂度是O n ∗ ( n + 1 ) 2 − 1 {\sqrt{n}*(\sqrt{n}+1)\over2}-1 2n (n +1)1,或简写为O( n 2 \sqrt{n}^2 n 2)。在大O表示法中,我们通常省略掉常数因子和低阶项,因此简化为O( n \sqrt{n} n )。
在这里插入图片描述

题目2:输入三个整数,按由小到大的顺序输出。

看到这种题,不用多说,sort直接秒了!

package lanqiao_study;

import java.util.Arrays;
import java.util.Scanner;

public class 三数大小判断 {

	public static void main(String[] args) {
		//题目:输入三个整数,按由小到大的顺序输出。
		//1.输入三个整数
		Scanner sc = new Scanner(System.in);
		int[] nums = new int[3];
		for(int i = 0;i < 3;i++) {
			nums[i] = sc.nextInt();
		}
		//排序,Arrays.sort排序默认升序(从小到大)
		Arrays.sort(nums);
		System.out.println(nums[0]+" "+nums[1]+" "+nums[2]+" ");

	}

}

这段代码的时间复杂度是O(1)。

计算时间复杂度的过程如下:

  1. 输入三个整数,时间复杂度为O(1)。
  2. 使用Arrays.sort对数组进行排序,时间复杂度为O(nlogn),其中n为数组的长度,这里n=3,所以时间复杂度为O(1)。
  3. 输出排序后的数组,时间复杂度为O(1)。

综上所述,整个代码的时间复杂度为O(1)。
在这里插入图片描述

题目3:输入两个正整数m和n,求其最大公约数和最小公倍数。

了解一下最大公约数和最小公倍数:如果数a能被数b整除,a就叫做b的倍数,b就叫做a的约数。约数和倍数都表示一个整数与另一个整数的关系,不能单独存在。如只能说16是某数的倍数,2是某数的约数,而不能孤立地说16是倍数,2是约数。

package lanqiao_study;

import java.util.Scanner;

public class 最大公约最小公倍 {

	public static void main(String[] args) {
		//题目:输入两个正整数m和n,求其最大公约数和最小公倍数。
		//1.输入两个正整数
		Scanner sc = new Scanner(System.in);
		int m = sc.nextInt();
		int n = sc.nextInt();
		int sum = m * n;
		boolean isFlag = true;
		int x = 1;
		while(isFlag) {
			if(x == 0)break;else isFlag = true;
			x = m % n;
			m = n;
			n = x;
		}
		System.out.println(m+" "+sum/m);
	}

}

这段代码的时间复杂度是O(logn)。

计算时间复杂度的过程如下:

  1. 输入两个正整数m和n,时间复杂度为O(1)。
  2. 使用辗转相除法求最大公约数,时间复杂度为O(logn),其中n为两个正整数中较小的那个。
  3. 输出最大公约数和最小公倍数,时间复杂度为O(1)。

综上所述,整个代码的时间复杂度为O(logn)。
在这里插入图片描述

题目4:古希腊数学家毕达哥拉斯在自然数研究中发现,220的所有真约数(即不是自身的约数)之和为:

1+2+4+5+10+11+20+22+44+55+110=284。

而284的所有真约数为1、2、4、71、 142,加起来恰好为220。人们对这样的数感到很惊奇,并称之为亲和数。一般地讲,如果两个数中任何一个数都是另一个数的真约数之和,则这两个数就是亲和数。
你的任务就编写一个程序,判断给定的两个数是否是亲和数

题目解析:将一个数的约数之和与另一个数比较,另一个书的约数之和和第一个数比较,如果相等,那么则是亲和数

package test;

import java.util.Scanner;

public class is亲和数 {
	public static void main(String[] args) {
		/*
		 * 古希腊数学家毕达哥拉斯在自然数研究中发现,220的所有真约数(即不是自身的约数)之和为: 
		 * 1+2+4+5+10+11+20+22+44+55+110=284。 
		 * 而284的所有真约数为1、2、4、71、 142,加起来恰好为220。
		 * 人们对这样的数感到很惊奇,并称之为亲和数。
		 * 一般地讲,如果两个数中任何一个数都是另一个数的真约数之和,则这两个数就是亲和数。 
		 * 你的任务就编写一个程序,判断给定的两个数是否是亲和数
		 */
		//1.读取数据
		Scanner sc = new Scanner(System.in);
		int m = sc.nextInt();
		int[] nums = new int[2*m];
		for(int i = 0;i < 2*m;i++) {
			nums[i] = sc.nextInt();
		}
		//2.判断是否为亲和数,一次判断一对
		for (int i = 0; i < 2*m; i+=2) {
			int sum1 = isAN(nums[i]);
			int sum2 = isAN(nums[i + 1]);
			if (sum1 == nums[i + 1] && sum2 == nums[i]){
				System.out.println("YES");
		}else {
				System.out.println("NO");
			}

		}
	}

	private static int isAN(int num) {
		int sum = 0;
		for (int i = 1; i < num; i++) {
			if (num % i == 0){
				sum+=i;
			}
		}
		return sum;
	}
}


算法时间复杂度分析:

这段代码的时间复杂度是O(n^2)。

计算时间复杂度的过程如下:

  1. 读取数据部分,需要读取2m个整数,时间复杂度为O(m)。
  2. 判断是否为亲和数的部分,需要进行2m次循环,每次循环内部调用isAN函数。
  3. isAN函数的时间复杂度为O(n),因为它需要遍历从1到num-1的所有整数,求出num的真约数之和。
  4. 因此,判断是否为亲和数的部分的总时间复杂度为O(2m * n) = O(mn)。
  5. 综合以上各部分,整个程序的时间复杂度为O(m + mn) = O(mn)。

在这里插入图片描述

第5题:德国数学家哥德巴赫曾猜测:任何大于6的偶数都可以分解成两个素数(素数对)的和。但有些偶数可以分解成多种素数对的和,如: 10=3+7,10=5+5,即10可以分解成两种不同的素数对

题目分析:这道题核心就两步:1.找素数;2.找素数对

package test;

import java.util.ArrayList;
import java.util.Scanner;

public class 素数和 {

	public static void main(String[] args) {
		/*
		 * 题目:德国数学家哥德巴赫曾猜测:任何大于6的偶数都可以分解成两个素数(素数对)的和。
		 * 但有些偶数可以分解成多种素数对的和,如: 10=3+7,10=5+5,即10可以分解成两种不同的素数对
		 * 
		 * 输入要求:输入任意的>6的正偶数(<32767)
		 */
		//1.输入
		Scanner sc = new Scanner(System.in);
		int num = sc.nextInt();
		//判断该数是否越界
		if(num <= 6 || num >= 32767) {
			System.out.println("0");
		}
		//如果未越界,则开始判断素数对的和的对数
		//2.判断对数
		//2.1首先找到这个数的所有素数,在依次增加,由于这个数是未知的,所以可以用集合来存放素数
		ArrayList<Integer> list = new ArrayList<>();//用于存放素数的集合
		boolean isFlag = false;
		for(int i = 2;i <= num;i++) {
			isFlag = true;
			for (int j = 2; j <= Math.sqrt(i); j++) {
				if(i % j == 0) {
					isFlag = false;
					break;
				}
			}
			if (isFlag){
				list.add(i);
			}
		}
		//当这个数的全部素数找完后,就可以开始计算成对的数量
		int count = 0;//用于计数
		for(int i = 0;i < list.size();i++) {
			for(int j = i;j < list.size();j++) {
				//如果两个素数加起来能够等于原数,则次数加1
				if(list.get(i) + list.get(j) == num) {
					count++;
				}
			}
		}
		System.out.println(count);
	}

}

但是要注意的是去重,不然结果就会错误

算法时间复杂度分析:

这段代码的时间复杂度是O(n^2)。

计算过程如下:

  1. 输入一个大于6的正偶数num,判断是否越界。
  2. 使用ArrayList存储素数,遍历从2到num的所有整数,判断每个整数是否为素数,时间复杂度为O(n)。
  3. 对于每个素数,再遍历一次ArrayList中剩余的素数,判断两个素数之和是否等于num,时间复杂度为O(n)。
  4. 因此,总的时间复杂度为O(n) * O(n) = O(n^2)。

在这里插入图片描述

题目6:输入一元一次方法的ax+b=0的解。且数据均在double类型以内,且一定有解(保留2位小数)

题目分析:这道题不难,只是将数学式子转为程序写法就ok,注意保留两位小数

package lanqiao_study;

import java.util.Scanner;

public class 求方程解 {

	public static void main(String[] args) {
		/*
		 * 题目:输入一元一次方法的ax+b=0的解。且数据均在double类型以内,且一定有解(保留2位小数)
		 */
		//1.输入两个数
		Scanner sc = new Scanner(System.in);
		double a = sc.nextDouble();
		double b = sc.nextDouble();
		System.out.printf("%.2f",(0 - b / a));
		
	}

}

时间复杂度分析:
时间复杂度为O(1)

在这里插入图片描述

题目7:对一个数十进制表示时的每一位数字乘五次方再求和,会得到一个数的五次方数

例如:1024的五次方数为1+0+32+1024=1057
有这样一些神奇的数,它的五次方数就是它自己,而且这样的数竟然只有有限多个
从小到大输出所有这样的数

题目分析:这道题有个坑,就是不知道边界,所以可以自己电脑上写一个死循环来看一下最大边界在哪

package lanqiao_study;

public class 五次方数 {

    public static void main(String[] args) {
        for (int a = 0; a < 10; a++)
            for (int b = 0; b < 10; b++)
                for (int c = 0; c < 10; c++)
                    for (int d = 0; d < 10; d++)
                        for (int e = 0; e < 10; e++)
                            for (int f = 0; f < 10; f++) {
                                int num = (int) (Math.pow(a, 5) + Math.pow(b, 5) + Math.pow(c, 5) + Math.pow(d, 5) + Math.pow(e, 5) + Math.pow(f, 5));
                                if (num == (a * 100000 + b * 10000 + c * 1000 + d * 100 + e * 10 + f) && num != 0 && num != 1)
                                    System.out.println(num);
                            }
    }
}

这段代码的时间复杂度是O(n^6)。

解析:

  1. 外层有6个嵌套的for循环,每个循环都从0到9,所以总共有10^6种可能的组合。
  2. 在每次循环中,都会计算一个五次方数的和,这个操作的时间复杂度是O(1)。
  3. 所以总的时间复杂度是O(n^6),其中n是循环的次数,这里是10。

题目8:给定N个整数组成的序列,每次交换当前第x个与第y个整数,要求输出最终的序列。

题目分析:这道题没有什么好说的,跟着题目一步一步走就行

package lanqiao_study;

import java.util.Scanner;

public class 交换序列 {

	public static void main(String[] args) {
		/*
		 * 给定N个整数组成的序列,每次交换当前第x个与第y个整数,要求输出最终的序列。
		 * 
		 * 输入要求:
		 * 第一行为序列的大小N(1< =N< =1000)和操作个数M(1< =M< =1000)。 
		 * 第二行包含N个数字,表示初始序列。
		 * 接下来M行,每行两个整数x,y  (1< =x,y< =N),表示要交换的两个整数。
		 * 在一次交换中,如果x和y相等,则不会改变序列的内容。 
		 */
		Scanner sc = new Scanner(System.in);
		//1.第一行为序列的大小N(1< =N< =1000)和操作个数M(1< =M< =1000)。 
		int n = sc.nextInt();
		int m = sc.nextInt();
		//2.第二行包含N个数字,表示初始序列。
		int[] nums = new int[n];
		for(int i = 0;i < n;i++) {
			nums[i] = sc.nextInt();
		}
		//3.接下来M行,每行两个整数x,y  (1< =x,y< =N),表示要交换的两个整数。
		while(m <= 1000 && m >= 1) {
			int x = sc.nextInt();
			int y = sc.nextInt();
			int temp = nums[x - 1];
			nums[x -1] = nums[y - 1];
			nums[y - 1] = temp;
			m--;
		}
		for(int i = 0;i < n;i++) {
			System.out.println(nums[i]);
		}
	}

}

这段代码的时间复杂度是O(n+m)。

解析:

  1. 输入序列的大小N和操作个数M,这个操作的时间复杂度是O(1)。
  2. 输入初始序列,这个操作的时间复杂度是O(n),其中n是序列的大小。
  3. 进行M次交换操作,每次交换操作的时间复杂度是O(1),所以总的时间复杂度是O(m)。
  4. 输出最终的序列,这个操作的时间复杂度是O(n)。

所以,总的时间复杂度是O(n+m)。

题目9:企业发放的奖金根据利润提成。利润低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元 时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;20万到40万之间时,高于20万元的部分,可提成5%;40万元到60万元 之间时高于40万元的部分,可提成3%;60万到100万之间时,高于60万元的部分,可提成1.5%;高于100万元时,超过100万元的部分按1%提 成。从键盘输入当月利润,求应发放奖金总数?(保留两位小数)利润的大小在double以内

题目分析:这道题比较考数学计算,要注意各阶段的利润计算,以及不要眼花

package lanqiao_study;

import java.util.Scanner;

public class 利润计算 {

	public static void main(String[] args) {
		/*
		 * 企业发放的奖金根据利润提成。
		 * 
		 * 利润低于或等于10万元时,奖金可提10%;
		 * 
		 * 利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;
		 * 
		 * 20万到40万之间时,高于20万元的部分,可提成5%;
		 * 
		 * 40万元到60万元  之间时高于40万元的部分,可提成3%;
		 * 
		 * 60万到100万之间时,高于60万元的部分,可提成1.5%;
		 * 
		 * 高于100万元时,超过100万元的部分按1%提成。
		 * 
		 * 从键盘输入当月利润,求应发放奖金总数?(保留两位小数)利润的大小在double以内
		 */
		//1.输入
		Scanner sc = new Scanner(System.in);
		double price = sc.nextDouble();
		//1.利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;
		if(price <= 10000) {
			//利润低于或等于10万元时,奖金可提10%;
			System.out.printf("%.2f",price*0.1);
		}else if(price <= 20000) {
			System.out.printf("%.2f",price*0.1+(price-100000)*0.075);
		}else if(price <= 40000) {
			System.out.printf("%.2f",100000*0.1+100000*0.075+(price - 200000) *0.05);
		}else if(price <= 600000) {
			System.out.printf("%.2f",100000*0.1+100000*0.075+200000*0.05+(price - 400000)*0.03);
		}else if(price <= 1000000) {
			System.out.printf("%.2f",100000 * 0.1 + 100000 * 0.075 + 200000 * 0.05 + 200000 * 0.03 + (price - 600000) * 0.015);
		}else {
			System.out.printf("%.2f",100000 * 0.1 + 100000 * 0.075 + 200000 * 0.05 + 200000 * 0.03 + 400000 * 0.015 + (price - 1000000) * 0.01);
		}
	}

}

时间复杂度为O(1)。

最后4道题太简单了就不做过多说明。

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值