leetcode -- Count of Smaller Numbers After Self -- 经典求逆序数
2015-12-25 19:46
549 查看
https://leetcode.com/problems/count-of-smaller-numbers-after-self/
这里当left[i]被合并之后, i 指针继续向前,j 可能变也可能不变,到达一个newinew_i, left[newinew_i] <=right[newjnew_j],这个时候依然是记上newjnew_j 次逆序。
参考https://leetcode.com/discuss/73256/mergesort-solution的思路
自己错误的code
正确的code
这里如何改造成最标准的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/
http://www.hrwhisper.me/binary-indexed-tree-fenwick-tree/
思路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/相关文章推荐
- (二) RIL 层分析
- ural 1069. Prufer Code
- Atitit. Derby的使用总结attilax
- cond--求矩阵的条件数
- Java多线程总结之线程安全队列Queue
- Atitit.java 反编译 工具 attilax 总结
- 走上一条归路:IOS I am coming
- Atitit.java 反编译 工具 attilax 总结
- 汇编指令总结
- sqrtm--矩阵的平方根
- hdu 4366 线段树+dfs序列
- (一) Porting USB 3G MODEM to Android
- Atitit.java 反编译 工具 attilax 总结
- u盘写保护
- DotNetOpenAuth Part 1 : Authorization 验证服务实现及关键源码解析
- 2015苏州大学ACM-ICPC集训队选拔赛(1) 1007
- 关于kafka的疑惑
- 321. Create Maximum Number(贪心)
- 深入剖析Android四大组件(九)——Activity之AppCompatActivity与toolbar的结合
- 2015苏州大学ACM-ICPC集训队选拔赛(1) 1006