493. Reverse Pairs

Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j].

You need to return the number of important reverse pairs in the given array.

Example1:

Input: [1,3,2,3,1]
Output: 2

 

Example2:

Input: [2,4,3,5,1]
Output: 3

 

Note:

  1. The length of the given array will not exceed 50,000.
  2. All the numbers in the input array are in the range of 32-bit integer.

拿到题目后,最直观的解法就是遍历尝试所有的(i, j)组合,看看有多少种组合满足 i < j and nums[i] > 2*nums[j]这一条件。

那么,写成代码就是一个嵌套的for循环:

result := 0
for
i:= 0; i < len(nums); i++ { for j := i; j < len(nums); j++ {
    if nums[i] > nums[j]*2 {
      result += 1
    } } }

可以想见,这样解法的时间复杂度为O(n²),空间复杂度为O(1)。

 

那么,有么有什么办法,可以把时间复杂度降低一些呢?

O(n*n)中,有个一个n是无法优化的,因为需要至少遍历每个元素一次,那么第二个n能否降低为<n的值呢?

想象一下,当我们从第0个元素往右遍历的时候,随着index的增加,我们能知道哪些信息?

(想象一个卷轴打开的样子,未打开的部分是未知的,已打开的部分就能看的内容)

 

对于这类顺序展开的情况,我们可以将其抽象成 f(i,j) = f(i, j-1) + c的情况。其中,可以假定f(i, j-1) 已知,我们通过解决c来完成f(i, j)的求解。

那么,在这道题目中,f(i, j-1) 和 c 分别是什么呢?

 

假设:

f(i, j-1) 代表 [i,j-1] 范围内,满足nums[i] > 2*nums[j] 这一条件的pair数。

c 代表以 j 为end时,一共可以新增多少个pair。

故,f(i,j) 就等于 f(i, j-1)已知的pair数 +  新增第j位后新出现的pair数

 

那么,如何求 c 呢?

 

以题目的第二个例子 [2,4,3,5,1] 举例:

nums 2 4 3 5 1
index 0 1 2 3
c 0 0 0 0 3
result 0 0 0 0 3


只需要数一下,[0, j-1] 范围内,有多少个元素大于 2*nums[j] 即可得到c。或者换一个角度,即统计在[0, len(nums)-1] 内大于 2*nums[j] 的元素中有多少个已经出现了。

 

我们可以将nums数组复制一个副本并排序,得到一个sorted[]数组,并用一个bit[]数组来标记哪些元素已经出现了(0表示元素还未出现,>0表示元素出现了若干次)。

那么,问题转变成求一个范围内的累加值,即:

idx := index(sorted, 2*nums[j]+1) //查找 2*nums[j]+1这数在sorted数组中的下标

result := sum(idx, len(sorted)-1) //计算bit[]数组 [idx, n-1] 区间的累加值

求指定范围内的累加值有几种方法:

1、for 循环遍历累加,时间复杂度O(n)

1 func rangeSum(nums []int, start, end int) int {
2   result := 0
3   for i := start; i <= end; i++ {
4     result += nums[i]
5   }
6   return result
7 }

当数组中的值有变化时,时间复杂度仍为O(0)

 

2、预先先算一个累计数组,即sum[];然后直接使用sum[j]-sum[i] 即可求得 [i, j]范围内的累加值。

 1 var sum []int
 2 func calcSums(nums []int)  {
 3   sum = make([]int, len(nums))
 4   lastSum := 0
 5   for i := 0; i < len(nums); i++ {
 6     sum[i] += nums[i] + lastSum
 7     lastSum = sum[i]
 8   }
 9 }
10 
11 func rangeSum(nums []int, start, end int) int {
12   return sum[end] - sum[start]
13 }

当数组不变时,预处理时间为O(n),取值的时间为O(1)

当数组元素变化时,需要O(n)时间来更新sum数组

 

3、segment tree

 

 1 func rangeSum(nums []int, start, end int) int {
 2     root := addNode(nums, 0, len(nums)-1)
 3     getSum(root, start, end)
 4 }
 5 
 6 type SegmentTreeNode struct{
 7   sum int
 8   start int
 9   end int
10   left *SegmentTreeNode
11   right *SegmentTreeNode
12 }
13 
14 func NewSegmentTreeNode(sum, start, end int, left, right *SegmentTreeNode) *SegmentTreeNode {
15     return  &SegmentTreeNode{
16         sum: sum,
17         start: start,
18         end: end,
19         left: left,
20         right: right,
21     }
22 }
23 
24 func addNode(nums []int, start, end int) *SegmentTreeNode {
25     if start == end {
26         return NewSegmentTreeNode(nums[start], start, end, nil, nil)
27     }
28     mid := (start+end)>>1
29     left := addNode(nums, start, mid-1)
30     right := addNode(nums, mid+1, end)
31     return NewSegmentTreeNode(left.sum+right.sum, start, end, left, right)
32 }
33 
34 func (node *SegmentTreeNode)update(idx, deltaVal int) {
35     if node.start == idx && node.end == idx {
36         node.sum += deltaValu
37         return
38     }
39 
40     mid := (node.start + node.end) >> 1
41     sum := 0
42     if idx >= mid {
43         if node.right != nil {
44             node.right.update(idx, deltaVal)
45             sum += node.right.sum
46         }
47     }else{
48         if node.left != nil {
49             node.left.update(idx, deltaValu)
50             sum += node.left.sum
51         }
52     }
53     node.sum = sum
54 }
55 
56 func getSum(root *SegmentTreeNode, start, end int) int {
57     if root.start == start && root.end == end {
58         return root.sum
59     }
60     //all in left subtree
61     if end < root.start {
62         if root.left == nil {
63             return 0
64         } 
65         return getSum(root.left, start ,end)
66     }
67     //all in right subtree
68     if start > root.end {
69         if root.right == nil {
70             return 0
71         }
72         return getSum(root.right, start ,end)
73     }
74     leftSum := getSum(root.left, start, root.start)
75     rightSum := getSum(root.right, root.right, end)
76     return leftSum+root.sum+rightSum
77 }
View Code

 segment tree的缺点是无法改变数组长度。

因为,为了保证查询时间是logn,因此在构造时使用了二分法保证树尽量平衡。

 

 4、fenwick tree

也称为 Binary Index Tree

 

 

 

 1 func reversePairs(nums []int) int {
 2     sorted := getSortedArray(nums)
 3     fenwickTree := NewFenwickTree(len(nums)+1)
 4     result := 0
 5     for i := 0; i < len(nums); i++{
 6         if 2*nums[i]+1 <= sorted[len(sorted)-1] {
 7             idx := index(sorted, 2*nums[i]+1)
 8             count := fenwickTree.getSum(len(fenwickTree.arr)-1) - fenwickTree.getSum(idx-1)
 9             result += count
10             fmt.Println(i, nums[i], idx, count, result, fenwickTree.arr)
11         }
12         //将nums[i]加入到fenwick tree中,让后面的元素可以看到它
13         fenwickTree.update(index(sorted, nums[i]), 1)
14     }
15     return result
16 }
17 
18 type FenwickTree struct {
19     arr []int
20 }
21 func NewFenwickTree(n int) *FenwickTree {
22     return &FenwickTree{arr: make([]int, n)}
23 }
24 func (ft *FenwickTree)update(idx, delta int) {
25     for ;idx < len(ft.arr); {
26         ft.arr[idx] += delta
27         idx += idx & -idx
28     }
29     //fmt.Println(idx, ft.arr)
30 }
31 func (ft *FenwickTree)getSum(idx int) int {
32     sum := 0
33     for ;idx > 0; {
34         sum += ft.arr[idx]
35         idx -= idx &-idx
36     }
37     return sum
38 }
39 
40 func index(sorted []int, val int) int {
41     l, r, m := 0, len(sorted)-1, 0
42     for ; l < r; {
43         m = (l+r) >> 1
44         if sorted[m] == val {
45             l = m
46             break
47         }else if sorted[m] > val{
48             r = m-1
49         }else{
50             l = m+1
51         }
52     }
53     //fmt.Println(val, l+1)
54     return l+1
55 }
56 
57 func getSortedArray(nums []int) []int {
58     list := make([]int, len(nums))
59     for i := 0; i < len(nums); i++ {
60         list[i] = nums[i]
61     }
62    
63     sort.Slice(list, func (i,j int) bool{
64         return list[i]<list[j]
65     })
66     return list
67 }
View Code

 

 

Reference:

https://leetcode.com/problems/reverse-pairs/discuss/97268/General-principles-behind-problems-similar-to-%22Reverse-Pairs%22

https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/

https://zh.wikipedia.org/zh-hans/%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84

http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=3513BBA8CE0ADA3B5520B42FA344D045?doi=10.1.1.14.8917&rep=rep1&type=pdf

posted @ 2020-01-19 21:37  elar  阅读(214)  评论(0编辑  收藏  举报