算法学习笔记2-递归问题的深入探讨/归并排序算法/小和问题算法

算法学习笔记-递归问题的深入探讨/归并排序算法/小和问题算法

说到这个问题呢,其实我们脑子里是不是第一感受是:
递归吗,自己调用自己咯。
在逻辑上讲,这没错,但事实又是如何呢,那我们进入第一个问题

递归问题的深入探讨

我们先来看一段代码吧

    int GetMax(int*Array,int Leftindex,int Rightindex){
        if(Leftindex==Rightindex)return Array[Leftindex];
        int minndex=(Leftindex+Rightindex)/2;
        return max(GetMax(Array,Leftindex,minndex),GetMax(Array,minndex+1,Rightindex));
    }

    int GetMin(int*Array,int Leftindex,int Rightindex){
        if(Leftindex==Rightindex)return Array[Leftindex];
        int minndex=(Leftindex+Rightindex)/2;
        return min(GetMin(Array,Leftindex,minndex),GetMin(Array,minndex+1,Rightindex));
    }

java代码如下
GetMaxValue .java

package sort;

/**
 * The type Get max value.
 *
 * @author user
 */
public class GetMaxValue {

    /**
     * Maxvalue int.
     *
     * @param array   the array
     * @param lefties the lefties
     * @param righted the righted
     * @return the int
     */
    public static int maxvalue(int[] array, int lefties, int righted) {
        if (lefties == righted) {
            return array[lefties];
        }
        int index=(lefties+righted)>>1;
        return Math.max(maxvalue(array,lefties,index),maxvalue(array,index+1,righted));
    }

    /**
     * Disorder int.
     *
     * @param args the args
     * @return the int
     */
    public static int disorder(int[] args) {
        int maxValue =args[0];
        for (int i = 1; i < args.length; i++) {
            if (args[i] > maxValue) {
                maxValue = args[i];
            }
        }
        return maxValue;
    }

    /**
     * Generate array int [ ].
     *
     * @return the int [ ]
     */
    public static int[] generateArray() {
        int maxValue = 123,minValue =1,randomMaximum=11, randomMinimum =-2;
        int length = (int) (Math.random() * maxValue)+minValue;
        int[] result = new int[length];
        for (int i = 0; i != length; i++) {
            result[i] = (int) (Math.random() * randomMaximum) + randomMinimum;
        }
        return result;
    }

    /**
     * The entry point of application.
     *
     * @param args the input arguments
     */
    public static void main(String[] args) {
        int testTime = 10000;
        boolean inorder= true;
        for (int i = 0; i <testTime; i++) {
            int[] array = generateArray();
            int maxValue = maxvalue(array, 0, array.length-1);
            if (disorder(array) != maxValue) {
                inorder = false;
                break;
            }
        }
        if (inorder) {
            System.out.println("666666");
        }else {
            System.out.println("333333");
        }
    }


}

GetMinValue .java

package sort;

/**
 * The type Get min value.
 *
 * @author user
 */
public class GetMinValue {

    /**
     * Minvalue int.
     *
     * @param array   the array
     * @param lefties the lefties
     * @param righted the righted
     * @return the int
     */
    public static int minvalue(int[] array, int lefties, int righted) {
        if (lefties == righted) {
            return array[lefties];
        }
        int index=(lefties+righted)>>1;
        return Math.min(minvalue(array,lefties,index),minvalue(array,index+1,righted));
    }

    /**
     * Disorder int.
     *
     * @param args the args
     * @return the int
     */
    public static int disorder(int[] args) {
        int maxValue =args[0];
        for (int i = 1; i < args.length; i++) {
            if (args[i] < maxValue) {
                maxValue = args[i];
            }
        }
        return maxValue;
    }

    /**
     * Generate array int [ ].
     *
     * @return the int [ ]
     */
    public static int[] generateArray() {
        int maxValue = 123,minValue =1,randomMaximum=11, randomMinimum =-2;
        int length = (int) (Math.random() * maxValue)+minValue;
        int[] result = new int[length];
        for (int i = 0; i != length; i++) {
            result[i] = (int) (Math.random() * randomMaximum) + randomMinimum;
        }
        return result;
    }

    /**
     * The entry point of application.
     *
     * @param args the input arguments
     */
    public static void main(String[] args) {
        int testTime = 10000;
        boolean inorder= true;
        for (int i = 0; i <testTime; i++) {
            int[] array = generateArray();
            int maxValue = minvalue(array, 0, array.length-1);
            if (disorder(array) != maxValue) {
                inorder = false;
                break;
            }
        }
        if (inorder) {
            System.out.println("666666");
        }else {
            System.out.println("333333");
        }
    }
}

其实我们不难发现,其实递归问题的算法可以改成非递归算法。
那递归的实质又是什么呢?
递归的实质是栈的自动的压入和弹出
不懂的话,请参见栈的压入和弹出
master公式及其应用

t(n)=at(n/b)+O(n^d);
n为数据总量,b为平均分成几份,a为出现的次数,O(n^d)为额外时间复杂度
if(log(b,a))>d=>O(n
log(b,a);
else if(log(b,a)==d)=>O(n^d*log(b,a));
else log(b,a)<d =>O(n^d);
master前提:你划分的子过程的规模是一样的。

归并排序

对于上面的问题就说这么多吧,我们来思考一下,我们对于排序应该有一定理解吧,那相信大家一定也对归并排序有一定理解吧,那请允许我在这里给大家总结一下吧。
其实我们可以把归并排序看成二分法的用法之一,先左侧排好序,在右侧排好序,再用一个辅助数组进行操作。那它的时间复杂度又是多少呢。
它的时间复杂度为:O(nlog(b,a))*

话不多说,上代码吧:

 void MergerSort(int Array[], int Lenght){
        int *Arrayhelp = new int[Lenght];
        mergeSortHelper(Array, Arrayhelp, 0, Lenght - 1);
        delete[] Arrayhelp;
    }
 void Merger(int Array[], int Arrayhelp[], int Left, int Mid, int Right){
        int i = Left,j = Mid + 1,k = Left;
        while (k <= Right) {
            if (i > Mid)Arrayhelp[k++] = Array[j++];
            else if (j > Right)Arrayhelp[k++] = Array[i++];
            else Arrayhelp[k++]=Array[i]>Array[j]?Array[j++]:Array[i++];
        }
        for (int k = Left; k <= Right; k++)Array[k] = Arrayhelp[k];
    }
 void mergeSortHelper(int Array[], int Arrayhelp[], int Left, int Right){
        if (Left >= Right) return;
        int Mid = (Left + Right)/2;
        mergeSortHelper(Array, Arrayhelp, Left, Mid);
        mergeSortHelper(Array, Arrayhelp, Mid + 1, Right);
        Merger(Array, Arrayhelp, Left, Mid, Right);
    }   

java代码如下

package sort;

import java.util.Arrays;

/**
 * The type Sort merge sort.
 * @author user
 */
public class SortMergeSort {

    /**
     * Get merge sort int [ ].
     *
     * @param array the array
     * @return the int [ ]
     */
    public static int[] getMergeSort(int[] array) {
        int minIndex=2;
        if (array == null || array.length <minIndex) {
            return array;
        }
        return mergeSort(array, 0, array.length - 1);
    }

    private static int[] mergeSort(int[] arr, int left, int right) {
        if (left == right) {
            return arr;
        }
        int mid = left + ((right - left)>>1);
        mergeSort(arr, left, mid) ;
        mergeSort(arr, mid + 1, right);
        return merge(arr, left, mid, right);
    }


    /**
     * Merge int [ ].
     *
     * @param arr    the arr
     * @param left   the left
     * @param madder the madder
     * @param right  the right
     * @return the int [ ]
     */
    public static int[] merge(int[] arr, int left, int madder, int right) {
        int[] help = new int[right - left + 1];
        int i = 0,p1 = left,p2 = madder + 1;
        while(p1 <= madder && p2 <= right) {
            if (arr[p1] < arr[p2]) {
                help[i++] = arr[p1++];
            }else {
                help[i++] = arr[p2++];
            }
        }
        while(p1 <= madder) {
            help[i++] = arr[p1++];
        }
        while(p2 <= right) {
            help[i++] = arr[p2++];
        }
        System.arraycopy(help, 0, arr, left, help.length);
        return arr;
    }

    /**
     * Disorder boolean.
     *
     * @param args the args
     * @return the boolean
     */
    public static boolean disorder(int[] args) {
        for (int i = 0; i < args.length-1; i++) {
            if (args[i]>args[i+1]) {
                return false;
            }
        }
        return true;
    }

    /**
     * Get random array int [ ].
     *
     * @return the int [ ]
     */
    public static int[] getRandomArray() {
        int[] res = new int[(int) (Math.random() * 20) + 1];
        for (int i = 0; i < res.length; i++) {
            res[i] = (int) (Math.random() * 20) + 1;
        }
        return res;
    }

    /**
     * The entry point of application.
     *
     * @param args the input arguments
     */
    public static void main(String[] args) {
        int testTime = 10000;
        boolean inorder= true;
        for (int i = 0; i <testTime; i++) {
            int[] array = getRandomArray();
            getMergeSort(array);
            if (!disorder(array)) {
                System.out.println(Arrays.toString(Arrays.stream(array).toArray()));
                inorder = false;
                break;
            }
        }
        if (inorder) {
            System.out.println("666666");
        }else {
            System.out.println("333333");
        }
    }
}

小和问题算法问题

在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
例子

[1,3,4,2,5]
 1左边比1小的数:没有
 3左边比3小的数:1
 4左边比4小的数:1,3
 2左边比2小的数:1
 5左边比5小的数:1,3,4,2
 所以小和为1+1+3+1+1+3+4+2=16

那思路又是什么呢:

这道题换个角度来想,题目要求的是每个数左边有哪些数比自己小,其实不就是右边有多少个数比自己大,那么产生的小和就是当前值乘以多少个吗?还是以上面的样例举例,1右边有4个比1大的数,所以产生小和14;3右边有2个比3大的数,所以产生小和32;4右边有一个比4大的数,所以产生小和41;2右边没有比2大的数,所以产生小和为20;5右边也没有比5大的数,所以产生小和5*0

算了,上代码吧:

    int LittleSums(int a[], int len){
        int *b = new int[len];
        int Liltlesum=littlesum(a, b, 0, len - 1);
        delete[] b;
        return Liltlesum;
    }
    
     int mergeSum(int a[], int b[], int l, int m, int r){
	    int Sum=0,i = l,j = m + 1,k = l;
        while (k <= r) {
            if (i > m) b[k++] = a[j++];
            else if (j > r) b[k++] = a[i++];
            else {
                if (a[i] > a[j]) b[k++] = a[j++];
                else {
            	    Sum+=a[i]*(r-j+1);
                    b[k++] = a[i++];
                }
            }
        }

        for(int k = l; k <= r; k++) a[k] = b[k];
        return Sum;
    }   

java代码实现:

/**
 * @version 0.1.2
 * @since 2021/10/24
 * @author Void Bug
 *
 * 问题描述:
 * 在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
 * 例子
 * [1,3,4,2,5]
 * 1左边比1小的数:没有
 * 3左边比3小的数:1
 * 4左边比4小的数:1,3
 * 2左边比2小的数:1
 * 5左边比5小的数:1,3,4,2
 * 所以小和为1+1+3+1+1+3+4+2=16
 *
 * 这道题换个角度来想,题目要求的是每个数左边有哪些数比自己小,
 * 其实不就是右边有多少个数比自己大,
 * 那么产生的小和就是当前值乘以多少个吗?
 * 还是以上面的样例举例,1右边有4个比1大的数,
 * 所以产生小和14;3右边有2个比3大的数,所以产生小和32;4右边有一个比4大的数,
 * 所以产生小和41;2右边没有比2大的数,所以产生小和为20;
 * 5右边也没有比5大的数,所以产生小和5*0
 *
 * 及我们先把左边右边都排好序,然后我们用左边的第0个值与右边第0个值的值
 * 如果大,那么就产生了左边元素第0个值*右边的个数,以此类推即可
 *
 * 不理解的话请参照上图(小和问题图解)即可
 */
public class Problematic_01_small {

    /**
     * 得到小和的方法,我们把数组传入,得到我们想要的小和值 mergeSort为具体实现方法
     * @param array 传入的数组
     * @return 返回小和值
     */
    public static int getSmallSum(int[] array) {
        if (array == null || array.length < 2) {
            return 0;
        }
        return mergeSort(array, 0, array.length - 1);
    }

    /**
     * 小和值的实现方法,我先把两边排好序,然后进行归并排序并进行计算小和值
     * mergeSort(arr, left, mid)/mergeSort(arr, mid + 1, right) 是把以中点断开左边和右边的数组进行拆分
     * merge(arr, left, mid, right) 进行排序并且计算小和值
     * @param arr 传入的数组
     * @param left 左端点值
     * @param right 右端点值
     * @return 我们想要的小和值
     */
    private static int mergeSort(int[] arr, int left, int right) {
        if (left == right) {
            return 0;
        }
        int mid = left + ((right - left)>>1);
        return mergeSort(arr, left, mid)
                + mergeSort(arr, mid + 1, right)
                + merge(arr, left, mid, right);
    }

    /**
     * 计算我们的小和值
     * 1.我们先去声明一个辅助数组
     * 2.我们去定义两个游标,让其中一个,本程序中是p1指向左半数组的第一个元素,让p2指向右半数组的第一个元素,用res去记录产生的小和值
     * 3.左边的游标值比右边的游标值小,则辅助数组中填入较小元素的值,并且计算出产生的小和值,小和值计算公式:(右边界到右游标的个数)个左标值
     * 4.以此类推即可
     * 5.当有一个游标到达左右的分水线时候,就说明了其中一个解决了,及全加到了array数组里面,我们把另一个加入即可
     * 6.把辅助数组的值复制到原来的数组即可,返回小和并且返回我们的排好序的数组即可
     *
     * 其实我们不难发现这与归并排序很像,几乎就没有差别,这个不难理解,我么不同的是就一个计算我们的小和即可
     *
     * @param arr 传入的数组
     * @param left 左端点值
     * @param right 右端点值
     * @param madder 中点位置
     * @return 返回我们的小和值并进行归并排序
     */
    private static int merge(int[] arr, int left, int madder, int right) {
        int[] help = new int[right - left + 1];
        int i = 0,p1 = left,p2 = madder + 1,res = 0;
        while(p1 <= madder && p2 <= right) {
            if (arr[p1] < arr[p2]) {
                res = res + arr[p1] * (right - p2 + 1);
                help[i++] = arr[p1++];
            }else {
                help[i++] = arr[p2++];
            }
        }
        while(p1 <= madder) {
            help[i++] = arr[p1++];
        }
        while(p2 <= right) {
            help[i++] = arr[p2++];
        }
        System.arraycopy(help, 0, arr, left, help.length);
        return res;
    }

    /**
     * 数组的对数器:生成随机数组,不定长不定值正整型数组
     * @return 返回生成的数组
     */
    public static int[] getRandomArray() {
        int[] res = new int[(int) (Math.random() * 20) + 1];
        for (int i = 0; i < res.length; i++) {
            res[i] = (int) (Math.random() * 20) + 1;
        }
        return res;
    }

    /**
     * 主方法
     * @param args 输入的信息
     * 测试方法
     */
    public static void main(String[] args) {
        int[] arr = {1,3,4,2,5};
        System.out.println(getSmallSum(arr));
    }
}

小和问题呢,个人感觉,难又不难,简单又不简单,虽然是写的不太好,但还是希望大家见谅吧。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值