数据结构和算法(2)断更一段时间,寒假开始更新

目录

查找最大值

归并排序O(nlgn)

小和问题


查找最大值

利用二分查找通过递归来找最大值

首先将数组通过中间元素arr[mid]将数组分为两个部分,两个部分分别递归,直到找到最大值

本质是一个多叉树,在计算树的所有的节点的时候,利用栈玩了一个后序遍历,每一个节点都通过自己的子节点给自己汇总信息之后才能够继续向上返回,栈空间就是整棵树的高度只需要在一个高度上进行压栈,这就是一个递归的过程

代码

public class Code6_getMax {
    public static int getMax(int[] arr) {
        return process(arr,0,arr.length-1);
    }//master公式
    public  static int process(int[] arr,int l,int r){
        if(arr.length==1){
            return arr[l];
        }
        int mid=l+((r-l)>>1);
        int lMax= process(arr,l,mid);
        int rMax=process(arr,mid+1,r);
        return Math.max(lMax,rMax);
    }
}

master公式

只要满足子问题具有相同规模的递归都可以用master公式

 总结

归并排序O(nlgn)

可以运用master公式来求解

左边先排好序,右边先排好序,左右merge在一起,整体就有序了

每一次的比较行为没有被浪费,每次比较最后会变成一个新的有序的数组,这种变成了有序的的东西,信息是往下传递的,正式因为这样它变成了O(n*lgn)

代码

public class Code7_mergeSort {
    public static void mergeSort(int[] arr){
        if(arr.length<2||arr==null){
            return ;
        }
        process(arr,0,arr.length);
    }
    public static void process(int[] arr,int l ,int r){
        if(l==r){
            return ;
        }
        int mid=l+((r-l)>>1);
        process(arr,l,mid);
        process(arr,mid+1,r);
        merge(arr,l,mid,r);
    }
    public static void merge(int[] arr,int l,int mid,int r){
        //左边已经有序,右边已经有序,通过merge使两边同时有序
        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(int ii=0;ii<help.length;ii++){
            arr[l+ii]=help[ii];
        }

    }
}

小和问题

1 3 4 2 5

1的左边没有比1小的数,所以小和为零

3的左边有1,所以小和是1

4的左边有3和1 ,所以小和是4

2的左边是1,小和是1

5的左边是1 3 4 2 所以小和是10

所以整个数组的小和是16

暴力解决很轻松,两层for循环就解决了,只不过时间复杂度是O(n2)

我们可以换一种思路来解决这个问题

看被查看的数字的右边有几个比他大的,有几个就算这个出现几次小和

如  1 出现的次数是4次

3出现的次数是2次

4出现的次数是1次

2出现的次数是1次

5出现的次数是0次

加起来也是16

所以这个可以用归并排序来进行解决

又与归并排序有一点不同,当左边的数等于右边的数的时候将左边的数放进外排序的数组里面,如果不这样做,就会不知道右边有多少个数比左边与右边相等的那个数大

 代码

public class Code8_SmallSum {
    public static int smallSum(int[] arr){
        if(arr.length==0||arr==null){
            return 0;
        }
        return mergeSort(arr,0,arr.length-1);

    }
    public static int mergeSort(int[] arr,int l,int r){
        if(l==r){
            return 0;
        }
        int mid=l+((r-l)>>1);
        return mergeSort(arr,l,mid)
                +mergeSort(arr,mid+1,r)
                +merge(arr,l,mid,r);



    }
    public static int merge(int[] arr,int l,int mid,int r){
        int[] help=new int[r-l+1];
        int i=0;
        int p1=l;
        int p2=mid+1;
        int ret=0;
        while(p1<=mid&&p2<=r) {
            ret += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p2] : 0;
            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(int j=0;j<help.length-1;j++){
            arr[l+j]=help[j];

        }
        return ret;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值