[每日一道小算法(四十七)] [数组] 数组中的逆序对(剑指offer)

前言:
今天借着这道题,又把归并排序算法学习了一下,总体来说收获还是挺大。

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

输入描述:

题目保证输入的数组中没有的相同的数字

数据范围:

	对于%50的数据,size<=10^4

	对于%75的数据,size<=10^5

	对于%100的数据,size<=2*10^5

示例1:

输入:
1,2,3,4,5,6,7,0
输出:
7

解题思路

看到这个题目,我首先就想到了暴力的解决办法。按顺序扫描整个数组。每扫描到一个数字,逐个比较该数字和他后面的数字的大小。如果后面的数字比他小,则这两个数字就组成一个逆序对。假设数组中含有n个数字。由于每个数字都要和O(n)个数字进行比较,因此这种算法的时间复杂度为O(n2)。这种方法可以解决问题,但是不是很好。所以就要想别的办法。借鉴了别人的思路,发现可以用归并排序方法,稍微变一下型就可以。
一会我会先将归并排序算法贴出来。先说一下归并排序算法的基本思想吧,归并排序算法其实就是将整个数组进行分解,分解到每个子数组长度都为,然后在两两子数组进行排序,这样一直操作,直到等于数组长度,结束操作。归并排序算法的时间复杂度是O(nlogn)。这个是要比O(n2)好的。在这里推荐一篇关于归并排序算法的详细讲解的博客,讲的特别好,可以借鉴一下。归并排序算法博客
上面只讲解了归并排序算法,下面我们就来说一说怎样利用排序算法来解决问题。我们在归并排序时,会分解到最后会是一个n个子数组,此时我们要进行两两排序,在排序比较的时候我们就可以找出逆序对。这里用两个指针p1、p2指向两个子数组的头部。然后进行比较如果此时第一个指针p1指向的数字大于p2指针指向的数字,就说明出现了逆序对。因为数组排好序的,所以p2指针到p1指针的数字都是大于p2指针的数字的,所以有几个数字就有几个逆序对,使用这样方法,就会找出所有的逆序对,并且不会出现漏的、重复的。

好啦不知道你们明白了没有,因为我这里不太会画图,所以只能口头描述了。如果没明白的,再看一看代码,相信你们会明白。

代码样例

归并排序

package com.asong.leetcode.InversePairsArray;

import sun.awt.image.PixelConverter;

/**
 * 归并排序
 */
public class SortDemo {
    public static void mergeSort(int[] array)
    {
        sort(array,0,array.length-1);
    }
    //递归分解
    public static void sort(int[] array,int low,int high)
    {
        if(low==high)
        {
            return;
        }
        int mid = low + ((high - low) >> 1);
        sort(array,low,mid);
        sort(array,mid+1,high);
        merge(array,low,mid,high);
    }
    //排序
    public static void merge(int[] array,int low,int mid,int high)
    {
        //用于保存排序数组
        int[] temp = new int[high-low+1];
        int i = 0;
        int p1 = low;
        int p2 = mid+1;
        //比较左右两部元素,那个小,把那个元素填入temp中
        while(p1<=mid && p2 <= high)
        {
            temp[i++] = array[p1] < array[p2] ? array[p1++] : array[p2++];
        }
        //上面循环退出后,把剩余的元素依次填入到temp中
        while(p1<=mid)
        {
            temp[i++] = array[p1++];
        }
        while(p2<=high)
        {
            temp[i++] = array[p2++];
        }
        //最终的排序结果复制给原数组
        for (int j = 0; j < temp.length; j++) {
            array[low+j] = temp[j];
        }
    }

    public static void main(String[] args) {
        int[] array = {8,1,3,6,2};
        mergeSort(array);
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
}

数组中的逆序对样例

package com.asong.leetcode.InversePairsArray;

import sun.awt.image.PixelConverter;

/**
 * 归并排序
 */
public class SortDemo {
    public static void mergeSort(int[] array)
    {
        sort(array,0,array.length-1);
    }
    //递归分解
    public static void sort(int[] array,int low,int high)
    {
        if(low==high)
        {
            return;
        }
        int mid = low + ((high - low) >> 1);
        sort(array,low,mid);
        sort(array,mid+1,high);
        merge(array,low,mid,high);
    }
    //排序
    public static void merge(int[] array,int low,int mid,int high)
    {
        //用于保存排序数组
        int[] temp = new int[high-low+1];
        int i = 0;
        int p1 = low;
        int p2 = mid+1;
        //比较左右两部元素,那个小,把那个元素填入temp中
        while(p1<=mid && p2 <= high)
        {
            temp[i++] = array[p1] < array[p2] ? array[p1++] : array[p2++];
        }
        //上面循环退出后,把剩余的元素依次填入到temp中
        while(p1<=mid)
        {
            temp[i++] = array[p1++];
        }
        while(p2<=high)
        {
            temp[i++] = array[p2++];
        }
        //最终的排序结果复制给原数组
        for (int j = 0; j < temp.length; j++) {
            array[low+j] = temp[j];
        }
    }

    public static void main(String[] args) {
        int[] array = {8,1,3,6,2};
        mergeSort(array);
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
}

发布了157 篇原创文章 · 获赞 34 · 访问量 4366

猜你喜欢

转载自blog.csdn.net/qq_39397165/article/details/104379841
今日推荐