蓝桥杯之排序与算法问题
一:排序
在一维数组中,排序是很重要的。下面是三种常用的排序算法:冒泡排序,插入排序,选择排序。
冒泡排序
原理:比较两个相邻的元素,将较大的值交换到右边
2 8 7 5 9 4 3
第一趟:
第一次:比较第一个和第二个: 2 和 8 ,不需要交换。
第二次:比较 8 和 7, 将8 和7 进行交换: 2 7 8 5 9 4 3
第三次:比较8 和5 ,将8 和5 交换 2 7 5 8 9 4 3
第四次:比较8 和 9 ,不需要交换
第五次:比较9 和 4 ,需要交换 2 7 5 8 4 9 3
第六次:比较9 和3 ,需要交换 2 7 5 8 4 3 9
第一趟结束后,最大的数字,出现在最后一位
第二趟:
第一次:比较2 和 7 ,不需要交换
第二次:比较7 和5 需要交换: 2 5 7 8 4 3 9
第三次:比较5 和 8 ,不需要交换
第四次:比较8 和4 ,需要交换:2 5 7 4 8 3 9
第五次:比较8 和3 ,需要交换:2 5 7 4 3 8 9
第六次:比较8 和9,不要交换(?)
第二趟,第二大的数字,出现在倒数第二位
以此类推:第三趟:2 5 4 3 7 8 9 第四趟。。。。。。直到排序完成。
简化:第一趟跑完,最大的数字在最后一位,不用参与排序,第二趟,第二大的 数字在倒数第二位,不用参与排序…
题目:排序:[10,1,35,61,89,36,55]
//外层for循环控制趟,内层控制次
int a [] = {10,1,35,61,89,36,55};
for (int i =0 ; i < a.length-1 ; i++){
for (int j =0 ; j< a.length-1-i; j++){
if(a[j]>a[j+1]){//左边大于右边
int k = a[j];
a[j] = a[j+1];
a[j+1] =k;
}
}
}
for (int i =0 ; i < a.length ;i++){
System.out.print(a[i] +" ");
}
选择排序:
原理:
第一次:从未排序的数据元素里面,选出一个最小的(最大的)的元素,然后和第一位元素交换位置。
第二次:选出第二小的(第二大的)的元素,然后和第二位元素交换位置。
…
int a [] = {2,9,5,0,1,3,6,8};
int begin =0;
int end = a.length-1;
while (begin <end){
int min = a[begin];//min,用来存储数组中元素的最小值
int t = begin;//t 存储最小值的下标
for (int i = begin; i <=end ; i++){
if(min > a[i]){
min = a[i];
t = i;
}
}
a[t] = a[begin];
a[begin] = min;
begin++;
}
for (int i =0 ; i < a.length ;i++){
System.out.print(a[i] +" ");
}
插入排序
原理:将数列分成两部分:排好序的数列 未排序的数列
在未排序的数列里面。挨个去元素插入到排好序的数列中
int a [] = {2,2,1,6,4,9,7,6,8};
for (int i =1 ; i < a.length ; i++){
int k = a[i];//哨兵。从数组第二位元素开始,每一循环向后移动一位存储元素,
// 将这个数插入到前面排好序的数列中
int j= i-1;//排好序的数列中的最后一位
while (j >=0&& k<a[j]){//哨兵要存在左边比它小,右边比它大
a[j+1] = a[j];//给哨兵的插入腾出位置
j--;//用j记录哨兵最终插入的位置
}
a[j+1] = k;//哨兵插入
}
for (int i =0 ; i < a.length ;i++){
System.out.print(a[i] +" ");
}
二:算法
递归
函数/方法 直接/间接 的调用本身。一般用来在数据原来的基础上加减乘除等操作。
案例:斐波那契数列:
1 1 2 3 5 8 13… 第一个和第二个数字是1,其他的数字等于前两个数字之和。Fn=F(n-1)+F(n-2)
代码:计算第n位的斐波那契数字
//递归:代码简洁,但是涉及到的运算,会随着递归层数的增加成指数级增长。
public static int Fn(int n){
if(n ==1 || n==2){
return 1;
}
return Fn(n-1)+Fn(n-2);
}
20年Java C组第三题:
如下图所示,小明用从 1 开始的正整数“蛇形”填充无限大的矩阵。
1 2 6 7 15 16 28 29…
3 5 8 14 17 27 30…
4 9 13 18 26 31…
10 12 19 25 32…
11 20 24 33…
21 23 34…
22 35…
容易看出矩阵第二行第二列中的数是5。请你计算矩阵中第20行第20列的数是多少?
- 分析:第20行20列处在45度这条线上。
这条线上的数字是:1 5 13 25 41 …两数之差: 4 8 12 16…
每一个都是在前面的基础上+4.可以用递归或者循环。 第n位和n-1位差 (n-1)*4
第20行20列相当于这个数列的第20位数字。
public static void main(String[] args) {
System.out.println(snack(20));
}
public static int snack(int n){
if(n ==1){
return 1;
}
return snack(n-1)+4*(n-1);
}
问题:递归和循环的关系?
一道题,可以用递归解答,
- 那么可以换成循环解决吗?可以换
- 代码量变多。运算资源(时间复杂度)
如果发现题目用递归运行时间超出限制,那么: - 换循环
- 加字典
- fn(5)= f(4)+f(3) f(4) = f(3)+f(2)[将f(3)和f(2)存起来] f(3)直接得出
辗转相除法:求最大公约数
- 两个整数的最大公约数等于其中较小的数和两数相除余数的最大公约数(gcd)
- gcd(a,b) = gcd(b ,a%b) a>b :当 b的值变成0的时候,a就是要求的最大公约数
- 案例:12和4的最大公约数 = 4 和 0 4
-
10 和7 的最大公约数 = 7 和3 = 3 和 1 = 1 和0
题目:输入两个数字,求最大公约数?
//循环解法
Scanner scan = new Scanner(System.in);
//a>b gcd(a,b) = gcd(b ,a%b) a>b
int a = scan.nextInt();
int b = scan.nextInt();
while (b!=0){
int c = a%b;
a =b;
b=c;
}
System.out.println(a);
//递归解法
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int a = scanner.nextInt();
int b = scanner.nextInt();
int zz = zz(a, b);
System.out.println(zz);
}
public static int zz(int a,int b){
if(b==0){
return a;
}
int c = a%b;
return zz(b,c);
}