IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 归并排序实现以及归并排序改写解决算法题 -> 正文阅读

[数据结构与算法]归并排序实现以及归并排序改写解决算法题

归并排序实现

归并排序大概思路:
归并时间复杂度:O(n*logn);
在这里插入图片描述
就是把一组数组从中间分成两组;记位左组,和右组;然后再把左右组继续分成新的左组右组,直到左组右组有序(左组和组内分别为都只有一个元素),然后将这两个有序的左右组有序的合成一个数组,就是图片中绿色部分的过程;接下来来结合代码更好的理解下吧 。代码如下:
递归版:

import java.util.Arrays;

public class t {

    public static void main(String[] args) {
        int[] arr = {1,3,2,5,4,6};

        guib(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }

    public static void guib(int[] arr,int l,int r){  //把数组分成左组和右组 
        if(l ==r){  
            return;
        }

        int m = l+(r-l)/2;
        guib(arr,l,m);
        guib(arr,m+1,r);
        mage(arr,l,r,m);





    }
    public static void mage(int[] arr,int l,int r,int m){ // 将左右组进行排序
        int[] hep = new int[r-l+1];  
        int p1 = l;
        int p2 = m+1;
        int i = 0;
        while (p1<=m && p2<=r){

            if(arr[p1]<=arr[p2]){
                hep[i] = arr[p1];
                i++;
                p1++;

            }else {
                hep[i] = arr[p2];
                i++;
                p2++;
            }


        }

        while(p1<=m){
            hep[i] = arr[p1];
            i++;
            p1++;
        }
        while(p2<=r){
            hep[i] = arr[p2];
            i++;
            p2++;

        }

        for(int j = 0;j< hep.length;j++){ //将排完的数在放回到原数组
            arr[l+j] = hep[j];



        }





    }




}

运行结果:
在这里插入图片描述
非递归版:

import java.util.Arrays;

public class t {

    public static void main(String[] args) {
        int[] arr = {1,3,2,5,4,6};
        int i = 1;
        int l = 0;
        int r = 0;
        while(i<arr.length){
            l = 0;
            while (l<arr.length){

               int m = l+i-1;
               if(m>arr.length-1){
                   break;
               }
               r = Math.min(arr.length-1,m+i);
               mage(arr,l,r,m);
               l =r+1;


            }
            i = i*2;




        }


        System.out.println(Arrays.toString(arr));
    }


    public static void mage(int[] arr,int l,int r,int m){ // 将左右组进行排序
        int[] hep = new int[r-l+1];
        int p1 = l;
        int p2 = m+1;
        int i = 0;
        while (p1<=m && p2<=r){

            if(arr[p1]<=arr[p2]){
                hep[i] = arr[p1];
                i++;
                p1++;

            }else {
                hep[i] = arr[p2];
                i++;
                p2++;
            }


        }

        while(p1<=m){
            hep[i] = arr[p1];
            i++;
            p1++;
        }
        while(p2<=r){
            hep[i] = arr[p2];
            i++;
            p2++;

        }

        for(int j = 0;j< hep.length;j++){ //将排完的数在放回到原数组
            arr[l+j] = hep[j];



        }





    }




}

运行结果:
在这里插入图片描述

改写归并完成算法题

一.第一种

1.小和问题:假设给定一个数组:arr ;请算出数组中左边小的数加起来的和是多少;
例如:arr = {1,3,2,4};左边比1小的数没有;
                        左边比3小的数:1;
                         左边比2小的数:1;
                         左边比4小的数: 1,2,3;
                         最后求出它们的和:1+1+1+2+3 =8;

解题代码:

import java.util.Arrays;

public class t {
   public static int k;

    public static void main(String[] args) {
        int[] arr = {1,3,2,4};
        int i = 1;
        int l = 0;
        int r = 0;
        pai(arr,0,arr.length-1);



        System.out.println(k);
    }

    public static void pai(int[] arr,int l,int r){
        if(l ==r){

            return;
        }
        int m = l+(r-l)/2;
        pai(arr,l,m);
        pai(arr,m+1,r);
        mage(arr,l,r,m);

    }

    public static void mage(int[] arr,int l,int r,int m){ // 将左右组进行排序
        int[] hep = new int[r-l+1];
        int p1 = l;
        int p2 = m+1;
        int i = 0;
        while (p1<=m && p2<=r){

            if(arr[p1]<arr[p2]){
                k = (r-p2+1)*arr[p1]+k;// 这里是用来记录和的

                hep[i] = arr[p1];
                i++;
                p1++;

            }else {
                hep[i] = arr[p2];
                i++;
                p2++;
            }


        }

        while(p1<=m){
            hep[i] = arr[p1];
            i++;
            p1++;
        }
        while(p2<=r){
            hep[i] = arr[p2];
            i++;
            p2++;

        }

        for(int j = 0;j< hep.length;j++){ //将排完的数在放回到原数组
            arr[l+j] = hep[j];



        }





    }




}

解题思路:题目说的是把数组左边小的数加起来,我们可以转换成找出右边大的数有几个然后用个数乘当前的数字;
例如:arr = {1,3,2,4} ;
右边比1大的数有3个:
右边比3大的数有1个;
右边比2大的数有1个;
右边比4大的数有0个;
所以最后的和就是:1X3+3X1+2X1+4X0 = 8;
这时候就可以用归并排序的改写就能完成了:归并可以把数组分成左组和右组:
在这里插入图片描述

举一反三题目一变形

2.同样的我们很容易可以看出第一题的核心就是找出右边大的数;同样我们也可以编程找出右边小的数:
代码如下:

import java.util.Arrays;

public class t {
    public static int k;

    public static void main(String[] args) {
        int[] arr = {3,2,1,2,4,0};
        int i = 1;
        int l = 0;
        int r = 0;
        pai(arr,0,arr.length-1);



        System.out.println(k);
    }

    public static void pai(int[] arr,int l,int r){
        if(l ==r){

            return;
        }
        int m = l+(r-l)/2;
        pai(arr,l,m);
        pai(arr,m+1,r);
        mage(arr,l,r,m);

    }

    public static void mage(int[] arr,int l,int r,int m){ // 将左右组进行排序
        int[] hep = new int[r-l+1];
        int p1 = l;
        int p2 = m+1;
        int i = 0;
        p1 = m;
        p2 = r;

        while (p1>=l && p2>=m+1){
            if(arr[p1]>arr[p2]){
                k = k+(p2-m);
                p1--;
            }else {
                p2--;
            }



        }
        p1 = l;
        p2 = m+1;


        while (p1<=m && p2<=r){

            if(arr[p1]<arr[p2]){
                //k = (r-p2+1)*arr[p1]+k;

                hep[i] = arr[p1];
                i++;
                p1++;

            }else {
                hep[i] = arr[p2];
                i++;
                p2++;
            }


        }

        while(p1<=m){
            hep[i] = arr[p1];
            i++;
            p1++;
        }
        while(p2<=r){
            hep[i] = arr[p2];
            i++;
            p2++;

        }

        for(int j = 0;j< hep.length;j++){ //将排完的数在放回到原数组
            arr[l+j] = hep[j];



        }





    }




}

这里k计算的是个数;

题目二

找出数组右边乘2还小的数的个数,例如arr = {1,4,1,2}
在1的右边没有比1小的数
在4的右边有比1小的数1和2,但是1乘2任然小于4;这个1就符合要找的数而2乘2不小于4,所以就不符合要找的数,
解题代码:
import java.util.Arrays;

public class t {
    public static int k;
    public static int e;
    public static int q;

    public static void main(String[] args) {
        int[] arr = {2,5,9,4};
        int i = 1;
        int l = 0;
        int r = 0;
        pai(arr,0,arr.length-1);




        System.out.println(q);
    }

    public static void pai(int[] arr,int l,int r){
        if(l ==r){

            return;
        }
        int m = l+(r-l)/2;
        pai(arr,l,m);
        pai(arr,m+1,r);
        mage(arr,l,r,m);

    }

    public static void mage(int[] arr,int l,int r,int m){ // 将左右组进行排序
        int[] hep = new int[r-l+1];
        int p1 = l;
        int p2 = m+1;
        int i = 0;
        p1 = m;
        p2 = r;
        while(p1>=l&&p2>=m+1){
            if(arr[p1]<=arr[p2]){

                p2--;
            }else {
                if(arr[p1]>arr[p2]*2){
                    q = (p2-m)+q;
                    p1--;
                    continue;
                }
                p2--;



            }


        }
        p1 = l;
        p2 = m+1;



        while (p1<=m && p2<=r){

            if(arr[p1]<=arr[p2]){



                hep[i] = arr[p1];
                i++;
                p1++;

            }else {



                hep[i] = arr[p2];
                i++;
                p2++;
            }


        }

        while(p1<=m){
            hep[i] = arr[p1];
            i++;
            p1++;
        }
        while(p2<=r){
            hep[i] = arr[p2];
            i++;
            p2++;

        }

        for(int j = 0;j< hep.length;j++){ //将排完的数在放回到原数组
            arr[l+j] = hep[j];



        }





    }




}

不难发现在归并排序中我们可以修改一些代码去解决一些算法题;而这种题的特征往往和关键字“左”或者“ 右”有关,因此我们以后做到数组题,题目里有左右关键词可以考虑下归并

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 02:14:53  更:2022-09-15 02:17:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 19:04:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码