算法的深入浅出--5.递归底层思想实例及图解剖析以及master公式的详细讲解以及归并排序思想与实例深入讲解以及归并解决小和问题

本文深入剖析递归原理及应用,通过实例说明递归如何求解数组最大值,揭示递归过程中的压栈与出栈机制。同时,详细讲解归并排序算法,包括其时间与空间复杂度分析,以及如何利用Master公式计算复杂度。最后,通过归并排序解决小和问题,提供完整的代码示例。
摘要由CSDN通过智能技术生成

时间复杂度O(N^2):太简单没啥要解释的了

额外空间复杂度O(1):在完成每个目标的过程中,在目标完成过程中增加的变量和对象占用的空间

递归的深入剖析

通过一个简单实例来分析:通过递归求一个数组中的最大值

public class GetMaxNum {
    public static int getMax(int[] arr,int L,int R){
        if (L==R){
            return arr[L];
        }
        int middle=(L+R)/2;
        int leftMax=getMax(arr,L,middle-1);
        int rightMax=getMax(arr,middle,R);
        return Math.max(leftMax,rightMax);
    }
}

接下来我们分析递归的底层是怎么实现的

递归的过程就是一个系统进行一个压栈的过程

从底层一路压栈上去,当到达了if判断的结束之后,系统就会进行一个出栈的过程,一步步往回出栈。

 总结来说:在逻辑上是自己调用自己,在系统中只是一个系统栈而已。所以说所有的递归都可以变成非递归,也就是迭代。

master公式的详细讲解

T:时间复杂度

N:样本量

以上面为例:

T(N)=a*T(N/b)+O(N^d)  --》   T(N)=2*T(N/2)+O(N^0)

T(N):指的是该算法完成某个目标所使用的所有时间;

2*T(N/2):上面程序将查询分为左右两边,也就是将样本平分了(N/2),又因为被平分了两半所以就要乘以2 ( 2*T(N/2) ),

O(N^0):主查询块以外的一些消耗,这里就是左右两边对比的消耗,只进行了一次比较所以N^d=1,也就是d=0

然后带入式子:

log(b,a):以b为底,log a

log(b,a) >d --》 log(2,2) > 0  满足了第一个,所以上面式子的复杂度就是O(N^log(2,2))  --》  O(N)

归并排序的深入讲解

时间复杂度O(N*logN),额外空间复杂度O(N)

思想:

假设:有一个无序数组:arr=5  3  6  2  0  1

首先将左边排好序,和右边排好序

然后创建一个空数组,对原数组左右两边进行比较:

首先比较a和b值:a>b

放入到空数组中:

移动b位置

继续比较a和b的值:a>b

移动b位置

 继续比较a和b的值:a>b

移动b位置,发现b已经没有了,直接拷贝a的数组

排序完成!

使用master公式计算:T(N)=2T(N/2)+O(N) 

log(b,a)=d,所以复杂度是N*log(N)

Coding:

将左右两边分别排好序

merge()方法

while语句中:排序的过程,如上面分析一样,比较两个p1和p2的值,然后赋值以及移动

 上面while语句一定会导致一个越界,这样的话,就需要将另外一个没有越界的值赋到后面

完整代码

package cn.mxl.work;

public class MergeSort {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] arr= {4,3,2,7,6,8,0,9};
		sortProcess(arr, 0, arr.length-1);
		for(int i : arr) {
			System.out.println(i);
		}
	}
	public static void sortProcess(int[] arr,int L,int R) {
		if(L == R) {
			return ;
		}
		int mid=L+((R-L)>>1);
		sortProcess(arr,L,mid);
		sortProcess(arr,mid+1,R);
		merge(arr,L,mid,R);
	}
	private static void merge(int[] arr, int L, int mid, int R) {
		// TODO Auto-generated method stu
		int[] help=new int[R-L+1];
		int i=0;
		int p1=L;
		int p2=mid+1;
		while(p1<=mid&&p2<=R) {
			help[i++]=arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
		}
//		两个必有且只有一个越界
		while(p1<=mid) {
			help[i++]=arr[p1++];
		}
		while(p2<=R) {
			help[i++]=arr[p2++];
		}
		for(i=0;i<help.length;i++) {
			arr[L+i]=help[i];
		}
	}
}

 归并解决小和问题

问题描述:

左右两边进行分治 ,将左边和右边分别排好顺序

左边的每个数字对于右边排好序的来说,当前值要被加(右边的长度-p2位置+1)次

  

完整代码:

public class SmallSum {
    public static int partitionSort(int[] arr,int L,int R){
        if (L==R){
            return 0;
        }
        int middle=L+((R-L)>>1);
        return partitionSort(arr,L,middle)
                +partitionSort(arr,middle+1,R)
                +merge(arr,L,middle,R);
    }

    private static int merge(int[] arr, int l, int middle, int r) {
        int pos1=l;
        int pos2=middle+1;
        int[] help=new int[r-l+1];
        int i=0;
        int res=0;
        while (pos1<=middle && pos2<=r){
            res+=arr[pos1]<arr[pos2]?(r-pos2+1)*arr[pos1]:0;
            help[i++]=arr[pos1]<arr[pos2]?arr[pos1++]:arr[pos2++];
        }
        while (pos1<=middle){
            help[i++]=arr[pos1++];
        }
        while ((pos2<=r)){
            help[i++]=arr[pos2++];
        }
        for (int j = 0; j < help.length; j++) {
            arr[l+j]=help[j];
        }
        return res;
    }

    public static void main(String[] args){
        int[] arr={1,3,4,2,5};
        int res = partitionSort(arr, 0, arr.length - 1);
        System.out.println(res);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值