leetcode -- Count of Smaller Numbers After Self -- 经典求逆序数

https://leetcode.com/problems/count-of-smaller-numbers-after-self/

思路1 merge sort

关于merge sort

归并排序的时候,会先一直递归到只剩下两个元素,然后对这两个元素进行merge,merge到一个临时数组。在合并的过程中就肯定有元素之间的交换,只不过这里的不是在原来数组上in place交换,而是说直接赋值到一个临时数组里。参考http://www.jianshu.com/p/ae97c3ceea8d

具体思路

有很多思路可以参考,不过都是O(nlogn),最经典的思路就是做merge sort。因为merge sort中,要进行合并,合并的时候就可以有大小关系的体现。例如,merge sort的时候先把nums按中点分为left和right,当left和right都有序之后,如果没有逆序的话,left的所有的数应该要小于right的数,left = {a1,a2,a3}, right = {b1,b2,b3},i = j = 0. 如果i = j = 1的时候,a2>b2>b1, 对于a2就应该记2次逆序,这里不要用left[i] > right[j]时就记录一次逆序(自己错误的code里面写了例子)。而是要用left[i] <=right[j]时,这个时候证明,有0-(j-1)这么多的元素,都是left[i] > right[j],即left[i]的逆序,所以这里为left[i]记上j次逆序即可。例如left = {5,6,7}, right = {1,2,3}, j肯定等于3的时候,再对i = 0的元素5对应的逆序数加上3.对应code看看。然后这些跟left[i]逆序的元素在合并之后就ordered了,对于left[i], 再继续递归看看还是否存在right部分,继续在合并的过程中找逆序,找到逆序之后又合并消除逆序,然后。。。。递归。

这里当left[i]被合并之后, i 指针继续向前,j 可能变也可能不变,到达一个 newi , left[ newi ] <=right[ newj ],这个时候依然是记上 newj 次逆序。

leetcode -- Count of Smaller Numbers After Self -- 经典求逆序数_第1张图片

参考https://leetcode.com/discuss/73256/mergesort-solution的思路

The smaller numbers on the right of a number are exactly those that jump from its right to its left during a stable sort. 
So I do mergesort with added tracking of those right-to-left jumps.

自己错误的code

class Solution(object):
    def countSmaller(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        def sort(enum):
            half = len(enum) / 2
            if half:
                left, right = sort(enum[:half]), sort(enum[half:])
                m, n = len(left), len(right)
                i = j = 0
                #print (left, right, enum, smaller)
                while i < m and j < n:
                    if left[i][1] > right[j][1]:
                        enum[i + j] = right[j]
                        smaller[left[i][0]] += 1 
                        #这里有问题,因为left = {a1,a2,a3}, right = {b1,b2,b3}, if a2>b2>b1, 对于a2就记了2次,
                        #但是当i移动到a3时,如果a3>b2>b1,此时应该对a3记2次,但是这里只记录了1次。
                        j += 1
                    else:
                        enum[i + j] = left[i]
                        i += 1

                while i < m:
                    enum[i + j] = left[i]
                    if left[i][1] > right[n - 1][1]:
                        smaller[left[i][0]] += n
                    i += 1

                while j < n:
                    enum[i + j] = right[j]
                    j += 1


            return enum
        smaller = [0] * len(nums)
        sort(list(enumerate(nums)))
        return smaller

正确的code

def countSmaller(self, nums):
    def sort(enum):
        half = len(enum) / 2
        if half:
            left, right = sort(enum[:half]), sort(enum[half:])
            m, n = len(left), len(right)
            i = j = 0
            while i < m or j < n:
                if j == n or i < m and left[i][1] <= right[j][1]:
                #这里简化了merge sort,去掉了当i先到m或者j先到n的情况,直接合并到这一个while里面了。
                #j == n意思就是说j到头了,i还有元素没有合并。说明剩下的元素比right部分所有的数都大,所以也要算上len(right)的逆序数。例如left = [5,6,7], right = [1,2,3]. 
                    enum[i+j] = left[i]
                    smaller[left[i][0]] += j#这里直接加j就行了,好好体会。比方说left = [5,6,7], right = [1,2,10].这里当j指向10的时候,就可以开始即逆序数了,i指向的5被串入结果数组,i++指向6,那么6至少也有现在j这么多得逆序数
                    i += 1
                else:
                    enum[i+j] = right[j]
                    j += 1
        return enum
    smaller = [0] * len(nums)
    sort(list(enumerate(nums)))
    return smaller

这里如何改造成最标准的merge sort code 呢??复习的时候再探索一下。
标准merge sort python

这里有java版本做参考
http://www.hrwhisper.me/leetcode-count-of-smaller-numbers-after-self/
http://interactivepython.org/runestone/static/pythonds/SortSearch/TheMergeSort.html
https://leetcode.com/discuss/74110/11ms-java-solution-using-merge-sort-with-explanation
这个ref有思路讲解
http://www.geeksforgeeks.org/counting-inversions/

自己重写一遍

class Solution(object):
    def countSmaller(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        def merge_sort(enums):

            mid = len(enums)/2
            if mid:
                nums1, nums2 = merge_sort(enums[:mid]), merge_sort(enums[mid:])
                i, j = 0, 0

                while i < len(nums1) or j < len(nums2):
                    #print i,j, len(nums1), len(nums2)
                    #if j == len(nums2) or nums1[i][1] < nums2[j][1]:bug 1:这里要加上i不越界的条件
                    #if j == len(nums2) or i < len(nums1) and nums1[i][1] < nums2[j][1]:bug2:这里要加上等号
                    if j == len(nums2) or i < len(nums1) and nums1[i][1] <= nums2[j][1]:
                        res[nums1[i][0]] += j
                        enums[i + j] = nums1[i]
                        i += 1
                    else:
                        enums[i + j] = nums2[j]
                        j += 1

            return enums




        res = [0]*len(nums)
        a = merge_sort(list(enumerate(nums)))
        return res

思路2 BIT/ FT

http://bookshadow.com/weblog/2015/12/06/leetcode-count-of-smaller-numbers-after-self/
http://www.hrwhisper.me/binary-indexed-tree-fenwick-tree/

思路3 BST

http://whatsme.net/2015/12/16/Count-of-Smaller-Numbers-After-Self/

你可能感兴趣的:(leetcode)