算法很美 java版 二

紫霞

蓝桥杯 java

算法练习题

递归

一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法

递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

递归一般用法

  • 找重复
  • 找变化
  • 找边界

案例

求n的阶乘

1
2
3
4
5
6
7
8
9
10
public static int f1(int n){

//结束条件
if(n == 1){
return 1;
}

//递归
return n * f1(n - 1);
}

显示i到j的数

1
2
3
4
5
6
7
public static void f2(int i,int j){
if(i > j){
return;
}
System.out.print(i + "\t");
f2(i + 1,j);
}

数组求和

1
2
3
4
5
6
7
8
9
10
11
12
13
public static int f3(int[] arr,int i){

if(i == arr.length - 1){
return arr[i];
}

if(i > arr.length - 1){

return 0;
}

return arr[i] + f3(arr,i+1);
}

字符串反转

1
2
3
4
5
6
7
8
public static String f4(String s,int end){

if(end == 0){
return s.charAt(end) + "";
}

return s.charAt(end) + f4(s,end - 1);
}

斐波那契数列

1、1、2、3、5、8、13、21、34、……

前两个相加等于第三个

1
2
3
4
5
6
7
8
public static int f5(int n){

if(n == 1 || n == 2){
return 1;
}

return f5(n - 1) + f5(n - 2);
}

最大公约数

两个或多个整数共有约数中最大的一个

1
2
3
4
5
6
public static int f6(int m,int n){
if(n == 0){
return m;
}
return f6(n,m % n);
}

小白上楼梯(递归设计)

楼梯有n阶台阶 小白一次可以上一阶 2阶 3阶 计算小白有多少种走完楼梯的方式

思路: 一个台阶1种方法 二个台阶2种方法 3个台阶4中该方法 4个台阶7种方法 依此类推

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static int f7(int n){

if(n == 0) {
return 1;
}

if(n == 1){
return 1;
}

if(n == 2){
return 2;
}

return f7(n - 1) + f7(n - 2) + f7(n - 3);
}

旋转数组的最小数字(改造二分法)

把一个数组最开始的若干个元素搬到数组的末尾 我们称之为数组的旋转 输入一个递增排序的数组的一个旋转 输出旋转数组的最小元素 例 数组{3,4,5,1,2} 为 {1,2,3,4,5}的一个旋转 该数组的最小值为1

思路:取中间值 检测左侧有序还是右侧有序 因为要旋转的部分一定在无序的那一部分当中 一直找,直到找到为止

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
static int min(int[] arr){
//最左边下标
int begin = 0;
//最右边下标
int end = arr.length - 1;

//没有旋转的情况下 直接返回最侧
if(arr[begin] < arr[end]){
return arr[begin];
}

while (begin + 1 < end){

//中间下标
int middle = (begin + end ) / 2;

//要么左侧有序 要么右侧有序
if(arr[middle] >= arr[begin]){
//数组中间左侧有序
begin = middle;
//右侧有序
}else{
end = middle;
}
}

//返回最小值
return arr[end];
}

public static void main(String[] args) {
//测试数组
int [] arr = {5,1,2,3,4};
//调用方法
int res = min(arr);
//打印输入
System.out.println(res);

int [] arr2 = {3,4,5,1,2};
int res2 = min(arr);
System.out.println(res2);
}

若中间的值和左边的值和右边的值相等比如1,0,1,1,1那么应该放弃这个算法,采用扫描法

在有空字符串的有序字符串数组中查找

有个排序后的字符串数组 其中散布着一些空字符串 找出给定字符串(肯定不是空字符串)的索引

思路: 找出中间量 依次进行比较 因为有序 所以只需多次使用二分法查找即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* 查找方法
* @param string 字符串数组
* @param s 要查找的串
* @return
*/
static int index(String[] string,String s){
//起始下标
int begin = 0;
//末尾下标
int end = string.length - 1;

//检索条件
while(begin < end){
//取中间下标方法
int middle = begin + ((end - begin) >> 1);

//如果是空串 中间下标右移
if(string[middle].equals("")){
middle++;
}

//校验 防止死循环
if(middle > end){
return -1;
}

//如果中间值比要查找的值大则在左侧继续
if(string[middle].compareTo(s) > 0){
end = middle - 1;
//如果中间值比要查找的值小则在右侧继续
}else if (string[middle].compareTo(s) < 0){
begin = middle + 1;
}else{
//返回相等的串
return middle;
}
}
//不符合则返回-1
return -1;
}

public static void main(String[] args) {
//测试数组
String[] arr = {"a", "", "ac", "", "ad", "b", "", "ba"};
//调用方法
int res = index(arr, "abc");
//打印输出
System.out.println(res);
}

String.compareTo(参数) 返回值

如果指定的数与参数相等返回0。

如果指定的数小于参数返回 -1。

如果指定的数大于参数返回 1。

最长连续递增子序列(部分有序)

(1,9,2,5,6,3,4,6,8,0)中最长的递增子序列为(3,4,6,8)

思路: 记录一个起始下标,在记录一个从起始下标开始的下标 依次移动 直到移动的下标的下一个元素比它小 则终止当前的移动 记录下从起始下标到这个移动下标的长度 然后从移动的下标的下一下标开始作为起始下标 在重复此操作 最多即可得出最长序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public static void main(String[] args) {

//定义一个数组
int[] arr = new int[]{1,9,2,5,6,3,4,6,8,0};

//打印信息
System.out.println(max(arr));

}

/**
* 找出最长序列
* @param arr
* @return
*/
public static int max(int[] arr){

//其实下标
int begin = 0;
//移动的下标
int index = 0;
//最长序列值
int max = 0;
//只要其实下标小于数组长度 - 1即可循环查找
while (begin < arr.length - 1){
//校验 找出递增序列 前一个比后一个值小即可继续移动下标
if(arr[index] <= arr[index + 1]){
//向右移动下标
index++;
//递增序列结束
}else{
//下标继续移动
index++;

//找到最大序列长度
if(max < (index - begin)){
//记录下当前递增序列的长度
max = index - begin;
}
//重新定义新的递增序列的起始下标
begin = index;
}
}
//返回最大序列长度
return max;
}

设计一个高效的求a的n次幂的算法

  • 普通算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 时间复杂度为O(n)型的算法
* @param a 底数
* @param n 指数
* @return
*/
public static int pow(int a,int n){

int result = 1;

for (int i = 0; i < n; i++){
result *= 2;
}

return result;
}

时间复杂度为 O(n)

  • 优化过的算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* 时间复杂度 O(lg n ) 算法
* @param a 底数
* @param n 指数
* @return
*/
public static int pow2(int a,int n){

//存放底数
int result = a;
//中间量倍数
int exec = 1;

//特殊情况 n == 0时
if(n == 0){
return 1;
}

//倍数翻倍与指数进行比较
while ((exec<<1) < n){

//求次幂
result *= result;

//翻倍
exec <<= 1;

}

//递归 因为翻了相对应的倍数 所以还差 n(总指数) - exec(翻的倍数) 次幂
return result * pow2(a,n - exec);
}

时间复杂度为O(lg n)

你知道的越多 你不知道的越多 嘿 我是小博 带你一起看我目之所及的世界……

-------------本文结束 感谢您的阅读-------------

本文标题:算法很美 java版 二

文章作者:小博

发布时间:2022年03月03日 - 17:15

最后更新:2022年03月03日 - 17:16

原始链接:https://codexiaobo.github.io/posts/2702675562/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。