算法篇二(分治思想下的归并排序)

分治思想下的归并排序

归并排序

 1.归并思想:首先把一个数组中的元素,按照某一方法,先拆分了之后,按照一定的顺序各自排列,然后再归并到一起,使得归并后依然是有一定顺序的 。
 2.归并排序算法可以利用递归的思想或者迭代的思想去实现。首先我们先把一个无序的数组去拆分,然后利用一定的规则,去合并。类似于二叉树的结构。其总的时间复杂度为O( n log n)。空间复杂度为 S(nlogn)

题目(Leetcode-面试51)

 题目:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
  例子:输入[7,5,6,4] 输出 5

解题

1.暴力求解法:一开始我使用的是暴力法,就是直接遍历,用前值去比较后值,如果前值大就加1 ,这样,这个程序的时间复杂度为o(n的平方),短的数组可能并不会有什么大的问题,但是数组长度太长的话,他的效率会非常的低。、
 代码如下:

    class Solution {
        public int reversePairs(int[] nums) {
            int count = 0;
            for(int i=0;i<nums.length-1;i++){
                for(int j=i+1;j<nums.length;j++){
                    if(nums[i]>nums[j]){
                        count++;
                    }
                }
            }
            return count;
        }
    }

2.归并排序:
 所有的逆序对来自于3个地方
  1.左边区间的逆序对,
  2.右边区间的逆序对,
  3.横跨两个区间的逆序对
 所以我们选择在第二个子区间归并回去的时候,计算逆序对的个数:
  代码如下:

class Solution {
    public int reversePairs(int[] nums) {
        int len = nums.length;
        int[] copy new int[len];

        if(len <2){
            return 0;
        }

        for(int i=0;i<len;i++){
            copy[i] = nums[i];
        }
        int[] temp = new int[len];

        return reversePairs(copy,0,len-1,temp);

    }


    private int reversePairs(int[] copy,int start,int end,int[] temp){
        if(start == end){
            return 0;
        }
        int mid = start + (end-start)/2;
        int leftPairs = reversePairs(copy,start,mid,temp);
        int rightPairs = reversePairs(copy,mid+1,end,temp);
        if(copy[mid]<copy[mid+1]){
            return leftPairs+rightPairs;
        }

        int crossPairs = mergeAndCount(nums, start, mid, end, temp);
        return leftPairs + rightPairs + crossPairs;
    }

    private int mergeAndCount(int[] copy,int start,int mid,int end,int[] temp){
        for(int i=start;i<end+1;i++){
            temp[i] = copy[i];
        }
        int i = start;
        int j = mid+1;
        for(int k=start;k<end+1;k++){

            // 有下标访问,得先判断是否越界
            if (i == mid + 1) {
                copy[k] = temp[j];
                j++;
            } else if (j == right + 1) {
                copy[k] = temp[i];
                i++;
            } else if (temp[i] <= temp[j]) {
                // 注意:这里是 <= ,写成 < 就不对,因为只有>时才是逆序对
                copy[k] = temp[i];
                i++;
            } else {
                copy[k] = temp[j];
                j++;

                // 在 j 指向的元素归并回去的时候,计算逆序对的个数,只多了这一行代码
                count += (mid - i + 1);
            }
        }
        return count;
        }
    }
}

文章作者: Kobe-Liu1
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Kobe-Liu1 !
 上一篇
算法篇三(查询数组中第二大的数) 算法篇三(查询数组中第二大的数)
查询数组中第二大的数冒泡排序 一开始的想法是冒泡排序,就是遍历两遍,重新排列数组,然后取第二大的数 代码如下: private int func1(int[] arr) { for (int i = 0; i <arr.l
2020-06-22 Kobe-Liu1
下一篇 
算法篇一(分治思想下的快速排序) 算法篇一(分治思想下的快速排序)
分治思想下的快速排序分治思想 1.分治法的设计思想:把一个难以解决的大问题,分割成几个规模较小的相同问题,然后处理这些小问题,最终解决这个大问题。 2.分治策略:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模
2020-06-17 Kobe-Liu1
  目录