您的位置:首页 > 其它

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

2015-12-25 19:46 549 查看
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 可能变也可能不变,到达一个newinew_i, left[newinew_i] <=right[newjnew_j],这个时候依然是记上newjnew_j 次逆序。



参考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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: