剑指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

# -*- coding: utf-8 -*-
# @Time         : 2019-07-12 11:39
# @Author       : Jayce Wong
# @ProjectName  : job
# @FileName     : inversePairs.py
# @Blog         : https://blog.51cto.com/jayce1111
# @Github       : https://github.com/SysuJayce

class Solution:
    """
    要计算数组中的逆序对的对数,那么最直观的做法就是遍历整个数组,将当前元素和后续的所有元素进行
    比较,然后累计有多少逆序对。

    另一种解法就是基于归并排序的解法。
    上述的解法的最大缺陷在于每个数字都要跟后续的所有数字进行比较,导致时间复杂度为O(n^2)。
    如果可以避免这么多次比较,就可以提高效率。
    效仿归并排序,我们先将一个数组不断对半分裂,先得到多个长度为1的数组,然后每两个相邻数组进行比较
    然后归并。
    **之所以要进行归并(将这两个相邻数组合并后排序)是因为如果不排序的话,在下一轮的比较的时候会出现
    重复计数的情况**
    由于进行了排序,在下一轮归并的时候只需要将两个数组的最大值进行比较,如果左边的数组的最大值大于
    右边数组的最大值,那么说明右边整个数组都可以跟左边数组的最大值组成逆序对,因此跳过左边数组最大
    值和右边剩余元素的比较。
    这种解法其实就是**降序的归并排序**。
    """

    def InversePairs(self, data):
        def split(start, end):
            # 先将整个数组对半分裂成若干个长度为1的数组
            if start < end:  # start < end,说明长度大于1,继续分裂
                mid = (start + end) >> 1
                split(start, mid)
                split(mid + 1, end)
                # 分裂完成后,对两个相邻数组进行归并
                # 两个数组的下标分别为[start, mid], [mid + 1, end]
                merge(start, mid, end)

        def merge(start, mid, end):
            # 由于我们这里的count是InversePairs()里的局部变量,
            # 所以用nonlocal关键字而非global
            nonlocal count
            # 由于是进行降序归并,因此从两个数组的末尾开始归并
            p1 = mid
            p2 = end
            while p1 >= start and p2 > mid:
                # 如果左边大于右边,说明组成了一个逆序对,
                # 计数器count增加数值为右边数组的剩余元素个数
                if data[p1] > data[p2]:
                    # count += end - p2 + 1
                    count += p2 - mid
                    # data_copy用于存储归并后的结果
                    data_copy.append(data[p1])
                    p1 -= 1
                else:
                    data_copy.append(data[p2])
                    p2 -= 1
            # 将左右数组剩余的元素加入data_copy中,由于是有其中一个数组完全为空了,所以事实上
            # 只将其中一个数组的元素加入data_copy中,而由于我们是利用递归实现的,这个数组也早
            # 已有序,因此归并后的结果data_copy是有序的
            for p in range(p1, start - 1, -1):
                data_copy.append(data[p])
            for p in range(p2, mid, -1):
                data_copy.append(data[p])
            # 将归并结果赋值到原数组中,注意这里赋值的顺序,我们要保证从小到大。
            while data_copy:
                data[start] = data_copy.pop(-1)
                start += 1

        if not data:
            return 0

        count = 0  # 用于统计逆序对的对数
        data_copy = []  # 辅助数组,用于存储两个相邻数组归并的临时结果
        split(0, len(data) - 1)
        return count % 1000000007

def main():
    solution = Solution()
    data = [364, 637, 341, 406, 747, 995, 234, 971, 571, 219, 993, 407, 416,
            366, 315, 301, 601, 650, 418, 355, 460, 505, 360, 965, 516, 648,
            727, 667, 465, 849, 455, 181, 486, 149, 588, 233, 144, 174, 557, 67,
            746, 550, 474, 162, 268, 142, 463, 221, 882, 576, 604, 739, 288,
            569, 256, 936, 275, 401, 497, 82, 935, 983, 583, 523, 697, 478, 147,
            795, 380, 973, 958, 115, 773, 870, 259, 655, 446, 863, 735, 784, 3,
            671, 433, 630, 425, 930, 64, 266, 235, 187, 284, 665, 874, 80, 45,
            848, 38, 811, 267, 575]
    # data = [1,2,3,4,5,6,7,0]
    print(solution.InversePairs(data))

if __name__ == ‘__main__‘:
    main()

原文地址:https://blog.51cto.com/jayce1111/2419774

时间: 2024-11-13 08:06:28

剑指offer:数组中的逆序对的相关文章

剑指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 思路:归并排序的思路.具体参考剑指

剑指offer——数组中的逆序对

数组中的逆序对 **(不会)数据结构--小和问题 逆序对问题 原文地址:https://www.cnblogs.com/SkyeAngel/p/8978980.html

剑指offer_数组中的逆序对

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P. 并将P对1000000007取模的结果输出. 即输出P%1000000007 本题采用归并排序,归并排序算法我在前一篇博客里写到过,在那个基础上进行修改即可!(强烈建议先理解归并排序的具体算法后,再来做此题) public class Solution36 { private int count = 0; //记录次数 private int[] copy ;

剑指Offer34 数组中的逆序对

1 /************************************************************************* 2 > File Name: 34_InversePairsInArray.c 3 > Author: Juntaran 4 > Mail: [email protected] 5 > Created Time: 2016年09月02日 星期五 20时05分05秒 6 *******************************

剑指offer-数组中的逆序对-数组-python

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000000007 输入描述: 题目保证输入的数组中没有的相同的数字 数据范围: 对于%50的数据,size<=10^4 对于%75的数据,size<=10^5 对于%100的数据,size<=2*10^5 class Solution: def InversePairs(self, data):

剑指 Offer —— 数组中重复的数字

数组中的重复数字 题目描述 牛课网链接 长度为 n 的数组里,所有数字都在 0 到 n-1 的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 7 的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字 2 或者 3.(牛课网这里弄成「那么对应的输出是第一个重复的数字 2」了) A 简单实现思路 借助外部数组 b,原数组中的数字记为外部数组的下标,外部数组的值来存储这个数字出现的次数.原数组中

python剑指offer数组中出现次数超过一半的数字

题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如果不存在则输出0. 思路: 两种思路.第一种思路,出现次数超过一半的数字,不管如何,必然这个数字位于数组中间的位置,因此可以采用类似于快排的划分的方法,找到位于数组中间的位置的数字,然后在顺序检索是否这个数字出现次数超过一半.第二种思路根据数组的特点,出现次数超过一半的数,他出现的次数比其他数字出

剑指offer——数组中出现次数超过一半的数字(c++)

题目描述数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如果不存在则输出0. 思路一遍历数组是保存两个值:一个是数字中的一个数字,另一个是次数.当遍历到下一个数字的时候,如果下一个数字和之前保存的数字相等,则次数加1:如果不同,则次数减1:如果次数为零,那么我们需要保存下一个数字,并把次数设置为1.由于我们要找的数字出现的次数比其他所有数字出现的次数之和还

剑指offer 数组中出现超过一半的数字

class Solution { public: int MoreThanHalfNum_Solution(vector<int> numbers) { if(numbers.empty()){ return 0; } if(numbers.size() == 1){ return numbers[0]; } int len = (int)numbers.size(); float target = len/2.0; map<int, int> m; for(int num: nu

剑指offer (36) 数组中的逆序对

题目:在数组中的两个数字如果前面一个数字大于后面一个数字,则这两个数字组成一个逆序对 题解分析: 首先应该想到很简单的一种解法,顺序遍历数组,对每个数,逐个比较该数字和其以后的数字,T(n) = O(n^2) (1)总体的意思就是将数组分成两段,首先求段内的逆序对数量,比如下面两段代码就是求左右两端数组段内的逆序对数量 count += Merge(data, temp, first, mid);//找左半段的逆序对数目 count += Merge(data, temp, mid + 1, e