递归
递归设计经验:
- 找重复(子问题)
1.找到一种划分方法
2.找到递推公式或者等价转换
都是父问题转化为求解子问题 - 找重复中的变化量→参数
- 找参数变化趋势→设计出口
根据参数变化的趋势,对边界进行控制,适时终止递归
一.切蛋糕思维:
例题1:求n的阶乘
import java.util.Scanner;
public class LianXi {
public static int f(int n){
if(n==1)
return 1;
return n * f(n-1);
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
System.out.println(f(n));
}
}
例题2:打印 i 到 j
import java.util.Scanner;
public class LianXi {
public static void f(int i, int j){
if(i>j)
return ;
System.out.println(i);
f(i+1,j);
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int i = in.nextInt();
int j = in.nextInt();
f(i,j);
}
}
例题3:求数组中所有元素的和
import java.util.Scanner;
public class LianXi {
public static int f(int []arr,int begin){
if(begin==arr.length-1)
return arr[begin];
return arr[begin] + f(arr,begin+1);
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int []arr = new int [N];
for(int i=0; i<N; i++){
arr[i] = in.nextInt();
}
int begin = in.nextInt();
System.out.println(f(arr,begin));
}
}
例题4:翻转字符串
import java.util.Scanner;
public class LianXi {
public static String f(String s, int end){
if(end==0)
return "" + s.charAt(0);
return s.charAt(end) + f(s,end-1);
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
String s = in.next();
int end = s.length() - 1;
System.out.println(f(s,end));
}
}
二.划不开,有没有递推公式?有没有等价转换?
例题5:求斐波那契数列
斐波那契数列问题等价于两个子问题:
·求前一项
·求前二项
·两项求和
import java.util.Scanner;
public class LianXi {
public static int f(int n){
if(n==1 || n==2)
return 1;
return f(n-1) + f(n-2);
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
System.out.println(f(n));
}
}
例题6:求最大公约数(辗转相除法)
import java.util.Scanner;
public class LianXi {
public static int gcd(int m, int n){
if(n==0)
return m;
return gcd(n,m%n);
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int m = in.nextInt();
int n = in.nextInt();
System.out.println(gcd(m,n));
}
}
例题7:递归形式进行插入排序
对数组0到倒数第一个元素进行排序:
等价于:
对数组的0到倒数第二个元素,这部分排序,然后把倒数第一个元素插入到这个有序的部分中。
import java.util.Scanner;
public class LianXi {
public static void insertSort(int []arr, int k){
//对数组0到k个元素进行排序
if(k==0)
return ;
insertSort(arr,k-1);
//将第k个元素插入到排序后的数组中
int x = arr[k];
int index = k-1;
while(index>-1 && x<arr[index]){
arr[index+1] = arr[index];
index--;
}
arr[index+1] = x;
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int []arr = new int [N];
for(int i = 0; i<N; i++){
arr[i] = in.nextInt();
}
System.out.println("初始数组为:");
for(int i = 0; i<arr.length; i++){
System.out.print(arr[i] + " ");
}
insertSort(arr,arr.length-1);
System.out.println("\n" + "排序后:");
for(int i = 0; i<arr.length; i++){
System.out.print(arr[i] + " ");
}
}
}
例题8:汉诺塔问题
1~N从A移动到B,C作为辅助
等价于:
1、1~N-1从A移动到C,B为辅助
2、把N从A移动到B
3、1~N从C移动到B,A为辅助
import java.util.Scanner;
public class LianXi {
public static void Han(int N, String from, String to, String help){
if(N==1){
System.out.println("move" + N + "from" + from + "to" + to);
return ;
}
Han(N-1, from, help, to);
System.out.println("move" + N + "from" + from + "to" + to);
Han(N-1, help, to, from);
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int N = in.nextInt();
Han(N, "A", "B", "C");
}
}
三.查找与排序
例题9:二分查找
全范围二分查找等价于三个子问题:
1、 左边找(递归)
2 、中间比
3、 右边找(递归)
注意:左查找和右查找只选其一
import java.util.Arrays;
import java.util.Scanner;
public class LianXi {
public static int binarySearch(int []arr, int lo, int hi, int key){
if(lo>hi)
return -1;
int mid = (lo + hi) / 2;
if(arr[mid]<key){
return binarySearch(arr, mid + 1, hi, key);
}
else if(arr[mid]>key){
return binarySearch(arr, lo, mid - 1, key);
}
else{
return mid;
}
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int []arr = new int[N];
//数组元素赋值
for(int i = 0; i<N; i++){
arr[i] = in.nextInt();
}
//数组元素排序
Arrays.sort(arr);
int key = in.nextInt();
int t = binarySearch(arr, 0, arr.length - 1, key);
if(t == -1)
System.out.println("查找失败");
else
System.out.println("查找成功");
}
}
例题10:查找与排序
1、二分查找与插入排序
import java.util.Scanner;
public class LianXi {
//数组元素排序
public static void insertSort(int []arr, int k){
//对数组0到k个元素进行排序
if(k==0)
return ;
insertSort(arr,k-1);
//将第k个元素插入到排序后的数组中
int x = arr[k];
int index = k-1;
while(index>-1 && x<arr[index]){
arr[index+1] = arr[index];
index--;
}
arr[index+1] = x;
}
//查找元素
public static int binarySearch(int []arr, int lo, int hi, int key){
if(lo>hi)
return -1;
int mid = (lo + hi) / 2;
if(arr[mid]<key){
return binarySearch(arr, mid + 1, hi, key);
}
else if(arr[mid]>key){
return binarySearch(arr, lo, mid - 1, key);
}
else{
return mid;
}
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int []arr = new int [N];
for(int i = 0; i<N; i++){
arr[i] = in.nextInt();
}
System.out.println("初始数组为:");
for(int i = 0; i<arr.length; i++){
System.out.print(arr[i] + " ");
}
insertSort(arr,arr.length-1);
System.out.println("\n" + "排序后:");
for(int i = 0; i<arr.length; i++){
System.out.print(arr[i] + " ");
}
int key = in.nextInt();
int t = binarySearch(arr, 0, arr.length - 1, key);
if(t == -1)
System.out.println("查找失败");
else
System.out.println("查找成功");
}
}
2、希尔排序
把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
import java.util.Scanner;
public class LianXi {
public static void shellSort(int []arr){
//设a为间隔
for(int a = arr.length/2; a > 0; a = a / 2){
for(int i = a; i < arr.length; i++){
int x = arr[i];
int index = i-a;
while(index > -1 && x<arr[index]){
arr[index+a] = arr[index];
index -= a;
}
arr[index+a] = x;
}
}
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int []arr = new int[N];
for(int i = 0; i < N; i++){
arr[i] = in.nextInt();
}
System.out.println("初始数组为:");
for(int i = 0; i < arr.length; i++){
System.out.print(arr[i] + " ");
}
System.out.println("\n");
shellSort(arr);
System.out.println("希尔排序后数组为:");
for(int j = 0; j < arr.length; j++){
System.out.print(arr[j] + " ");
}
}
}