说起递归,可能都比较熟悉。经典的汉诺塔和斐波那契数问题,相信在熟悉不过,那就从递归开始吧!
**递归**:简单来说就是,函数自己直接或者间接调用自己;递归算法对解决一大类问题很有效,它可以使算法简洁和易于理解。递归往往能给我们带来非常简洁非常直观的代码形势,从而使我们的编码大大简化,然而递归的思维确实很我们的常规思维相逆的,我们通常都是从上而下的思维问题, 而递归趋势从下往上的进行思维。这样我们就能看到我们会用很少的语句解决了非常大的问题,所以递归策略的最主要体现就是小的代码量解决了非常复杂的问题。
**使用递归满足的3个条件**:
(1)函数自己调用自己;
(2)有趋于终止的条件;
(3)有递归方程;
**分治法的基本思想**:将一个规模为n的问题,把它划分为k个子问题,且满足这些子问题之间相互独立、性质相同,递归求解这些子问题,将这些子问题的解合并之后可以得到原问题的解。
**分治法解决的问题具有的特征**:
(1)该问题缩小到一定程度就很容易求解;
(2)该问题具有最优子结构性质;
(3)利用该问题分解的子问题的解合并后可以得到原问题的解;
(4)该问题分解的子问题都是相互独立的;
说完理论,就来看些例子吧~
- 二分搜索技术
基本思想:将n个元素分成个数大致相同的凉拌,取a[n/2]与x进行比较;如果x=a[n/2],算法停止。如果x<a[n/2],则在数组a的左侧进行寻找;反之,在a的右侧寻找。
public class TestDemo {
public static int binarySearch(int[] a,int key){
int left = 0;
int right = a.length-1;
while(left <= right){
int middle = (left+right)/2;
if (key == a[middle]) {
return middle;
}
if (key > a[middle]){
left = middle+1;
}
else {
right = middle-1;
}
}
return -1;
}
public static void main(String[] args) {
int[] a = {1,3,4,5,7,8};
Scanner sc = new Scanner(System.in);
int key = sc.nextInt();
int ret = binarySearch(a,key);
System.out.println("你要找的数字的下标是" + ret);
}
}
算法的时间复杂度为O(logn);
- 合并排序
基本思想:将待排序元素分成大小大致相同的2个子集,分别对两个子集进行排序,最终将排好序的自己合并为所要求的排好序的集合;
public class Demo {
public static void merge(Comparable[] c,Comparable[] d,int l,int m,int r){
//合并c[1:m]和c[m+1:r]到d[1:r]
int i = 1;
int j = m+1;
int k = 1;
while((i <= m) && (j <= r)){
if (c[i].compareTo(c[j]) <= 0){
d[k++] = c[i++];
}else {
d[k++] = c[j++];
}
if (i>m){
for (int q = j; q <= r ; q++) {
d[k++] = c[q];
}
}else {
for (int q = i; q <= m ; q++) {
d[k++] = c[q];
}
}
}
}
public static void mergePass (Comparable[] x,Comparable[] y,int s){
//合并为大小为s的相邻子数组
int i = 0;
while(i<x.length-2*s){
merge(x,y,i,i+s-1,i+2*s-1);
i = i+2*s;
}
if (i+s < x.length){
merge(x,y,i,i+s-1,x.length-1);
}else {
for (int j = i; j < x.length; j++) {
y[j] = x[j];
}
}
}
}
时间复杂度:
当n≤1时,T(n) = O(1);
当n>1时,T(n) = O(nlogn);
- 快速排序:
基本思想:对输入的子数组a[p:r]进行以下操作
(1)分解:
将a[p:r]以a[p]为基准,把它分成a[p:q-1],a[q]和a[q+1,r],使得a[p:q-1]中的元素均小于等于a[q],a[q+1:r]中的元素均大于a[q]
(2)递归求解:调用快速排序,对a[p:q-1]和a[q+1:r]进行排序
(3)合并
import java.util.Arrays;
import java.util.Scanner;
public class QuickSort {
public static void quickSort(int[] arr, int low, int high) {
if (low >= high) {
return;
}
int left = low;
int right = high;
int temp = arr[low]; // 基准元素
while (low < high) {
while (low < high && arr[high] >= temp) {
high--;
}
if (low < high) {
arr[low] = arr[high];
low++;
}
while (low < high && arr[low] < temp) {
low++;
}
if (low < high) {
arr[high] = arr[low];
high--;
}
}
arr[low] = temp;
quickSort(arr, left, low - 1);
quickSort(arr, low + 1, right);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(); // 数组的长度
int[] arr = new int[n];
for (int i = 0; i < arr.length; i++) {
arr[i] = scanner.nextInt();
}
scanner.close();
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
}
算法的时间复杂性分析:
最好情况:T(n) = O(nlogn);
平均情况:T(n) = O(nlogn);
最坏情况:T(n) = O(n^2);