算法学习笔记1


一、归并排序。1

归并排序的实现代码看了很多,本人菜鸟一枚,理解的还是不够透彻,后来看到 chengxiao图解排序算法(四)之归并排序,才有一种恍然大悟的感觉,特做一下学习笔记,以便将来忘记了再来查看。

1.1 基本思想- 分而治之

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。分阶段可以理解为就是递归拆分子序列的过程,递归深度为log2n。

1.2 图解

1.2.1 分–递归拆分子序列

可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。分阶段可以理解为就是递归拆分子序列的过程,递归深度为log2n。

1.2.2 治–合并相邻有序子序列

再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。
在这里插入图片描述在这里插入图片描述

二、数组中的逆序对

2.1 题目描述

在这里插入图片描述

在这里插入图片描述
题目保证输入的数组中没有的相同的数字

2.2 思考

读完题目,首先要知道什么是逆序,其次就可以确定题目肯定和排序有关系。最后因为题目中已经规定输入的数组中没有的相同的数字,如果有相同的数字需要另外讨论,但是基本原理是一样的,这里暂时按照题目要求处理。
因为对冒泡排序比较熟悉,首先考虑了冒泡排序。
时间复杂度:O(N^2)
空间复杂度:O(1)
不出意外的,超时了。
在这里插入图片描述
那就只有考虑其他排序方法了,以归并排序为例。
平均时间复杂度均为O(nlogn)
空间复杂度:O(N)

在这里插入图片描述
由此也可以看出,归并排序能利用完全二叉树特性,而能利用完全二叉树特性的排序一般性能都不会太差,是稳定排序,它也是一种十分高效的排序。

2.3 代码实现

在函数内部开辟额外空间的做法很不好。因为这样会涉及到频繁的构建 vector 和析构vector,所以比较好的做法是:直接在最外层开辟一个足够大的数组,然后传引用到函数。2

代码如下:

class Solution {
public:
    int InversePairs(vector<int> data) {
        vector<int> tmp(data.size());//
        int res = 0;
        merge_sort__(data,tmp,0,data.size() - 1,res);
        return res;
    }
    
    void merge_sort__(vector<int> &arr, vector<int> &tmp,int l,int r,int &res){
        if(l >= r) return;
        int mid = l + ((r-l) >> 1);
        merge_sort__(arr,tmp,l,mid,res);
        merge_sort__(arr,tmp,mid+1,r,res);
        merge__(arr,tmp,l,mid,r,res);
    }
    
    void merge__(vector<int> &arr, vector<int> &tmp,int l,int mid,int r,int &res){
        int i = l, j = mid + 1, k = 0;
        while(i <= mid && j <= r){
            if(arr[i] < arr[j]) tmp[k++] = arr[i++];
            else{
                tmp[k++] = arr[j++];
                res += (mid - i + 1);
                res %= 1000000007;
            }
        }
        while(i<=mid) tmp[k++] = arr[i++];
        while(j<=r) tmp[k++] = arr[j++];
        for(int k=0, i=l; i<=r; ++i, ++k)
            arr[i] = tmp[k];
    }
};

在函数merge__对左子树和右子树进行合并的时候,

res += (mid - i + 1);

在这里插入图片描述

在这里插入图片描述

还有最后边界条件的判断:

while(i<=mid) tmp[k++] = arr[i++];
while(j<=r) tmp[k++] = arr[j++];

在这里插入图片描述

终于通过啦!
在这里插入图片描述



  1. https://www.cnblogs.com/chengxiao/p/6194356.html ↩︎

  2. https://blog.nowcoder.net/n/925dccc54b54416984f4d819ca3cd4ad?f=comment ↩︎

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐