Skip to content

Commit d345144

Browse files
committed
添加 problem 493
1 parent 8f65cf9 commit d345144

File tree

3 files changed

+175
-0
lines changed

3 files changed

+175
-0
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package leetcode
2+
3+
import (
4+
"sort"
5+
6+
"github.com/halfrost/LeetCode-Go/template"
7+
)
8+
9+
// 解法一 线段树,时间复杂度 O(n log n)
10+
func reversePairs(nums []int) int {
11+
if len(nums) < 2 {
12+
return 0
13+
}
14+
st, numsMap, indexMap, numsArray, res := template.SegmentCountTree{}, make(map[int]int, 0), make(map[int]int, 0), []int{}, 0
15+
numsMap[nums[0]] = nums[0]
16+
for _, num := range nums {
17+
numsMap[num] = num
18+
numsMap[2*num+1] = 2*num + 1
19+
}
20+
// numsArray 是 prefixSum 去重之后的版本,利用 numsMap 去重
21+
for _, v := range numsMap {
22+
numsArray = append(numsArray, v)
23+
}
24+
// 排序是为了使得线段树中的区间 left <= right,如果此处不排序,线段树中的区间有很多不合法。
25+
sort.Ints(numsArray)
26+
// 离散化,构建映射关系
27+
for i, n := range numsArray {
28+
indexMap[n] = i
29+
}
30+
numsArray = []int{}
31+
// 离散化,此题如果不离散化,MaxInt32 的数据会使得数字越界。
32+
for i := 0; i < len(indexMap); i++ {
33+
numsArray = append(numsArray, i)
34+
}
35+
// 初始化线段树,节点内的值都赋值为 0,即计数为 0
36+
st.Init(numsArray, func(i, j int) int {
37+
return 0
38+
})
39+
for _, num := range nums {
40+
res += st.Query(indexMap[num*2+1], len(indexMap)-1)
41+
st.UpdateCount(indexMap[num])
42+
}
43+
return res
44+
}
45+
46+
// 解法二 mergesort
47+
func reversePairs1(nums []int) int {
48+
buf := make([]int, len(nums))
49+
return mergesortCount(nums, buf)
50+
}
51+
52+
func mergesortCount(nums, buf []int) int {
53+
if len(nums) <= 1 {
54+
return 0
55+
}
56+
mid := (len(nums) - 1) / 2
57+
cnt := mergesortCount(nums[:mid+1], buf)
58+
cnt += mergesortCount(nums[mid+1:], buf)
59+
for i, j := 0, mid+1; i < mid+1; i++ { // Note!!! j is increasing.
60+
for ; j < len(nums) && nums[i] <= 2*nums[j]; j++ {
61+
}
62+
cnt += len(nums) - j
63+
}
64+
copy(buf, nums)
65+
for i, j, k := 0, mid+1, 0; k < len(nums); {
66+
if j >= len(nums) || i < mid+1 && buf[i] > buf[j] {
67+
nums[k] = buf[i]
68+
i++
69+
} else {
70+
nums[k] = buf[j]
71+
j++
72+
}
73+
k++
74+
}
75+
return cnt
76+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package leetcode
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
type question493 struct {
9+
para493
10+
ans493
11+
}
12+
13+
// para 是参数
14+
// one 代表第一个参数
15+
type para493 struct {
16+
nums []int
17+
}
18+
19+
// ans 是答案
20+
// one 代表第一个答案
21+
type ans493 struct {
22+
one int
23+
}
24+
25+
func Test_Problem493(t *testing.T) {
26+
27+
qs := []question493{
28+
29+
question493{
30+
para493{[]int{1, 3, 2, 3, 1}},
31+
ans493{2},
32+
},
33+
34+
question493{
35+
para493{[]int{2, 4, 3, 5, 1}},
36+
ans493{3},
37+
},
38+
39+
question493{
40+
para493{[]int{-5, -5}},
41+
ans493{1},
42+
},
43+
44+
question493{
45+
para493{[]int{2147483647, 2147483647, -2147483647, -2147483647, -2147483647, 2147483647}},
46+
ans493{9},
47+
},
48+
}
49+
50+
fmt.Printf("------------------------Leetcode Problem 493------------------------\n")
51+
52+
for _, q := range qs {
53+
_, p := q.ans493, q.para493
54+
fmt.Printf("【input】:%v 【output】:%v\n", p, reversePairs(p.nums))
55+
}
56+
fmt.Printf("\n\n\n")
57+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# [493. Reverse Pairs](https://leetcode.com/problems/reverse-pairs/)
2+
3+
4+
## 题目:
5+
6+
Given an array `nums`, we call `(i, j)` an **important reverse pair** if `i < j` and `nums[i] > 2*nums[j]`.
7+
8+
You need to return the number of important reverse pairs in the given array.
9+
10+
**Example1:**
11+
12+
Input: [1,3,2,3,1]
13+
Output: 2
14+
15+
**Example2:**
16+
17+
Input: [2,4,3,5,1]
18+
Output: 3
19+
20+
**Note:**
21+
22+
1. The length of the given array will not exceed `50,000`.
23+
2. All the numbers in the input array are in the range of 32-bit integer.
24+
25+
26+
## 题目大意
27+
28+
给定一个数组 nums ,如果 i < j 且 nums[i] > 2\*nums[j] 我们就将 (i, j) 称作一个重要翻转对。你需要返回给定数组中的重要翻转对的数量。
29+
30+
注意:
31+
32+
- 给定数组的长度不会超过 50000。
33+
- 输入数组中的所有数字都在 32 位整数的表示范围内。
34+
35+
36+
## 解题思路
37+
38+
39+
- 给出一个数组,要求找出满足条件的所有的“重要的反转对” (i,j)。重要的反转对的定义是:`i<j`,并且 `nums[i] > 2*nums[j]`
40+
- 这一题是 327 题的变种题。首先将数组中所有的元素以及各自的 `2*nums[i] + 1` 都放在字典中去重。去重以后再做离散化处理。这一题的测试用例会卡离散化,如果不离散化,Math.MaxInt32 会导致数字溢出,见测试用例中 2147483647, -2147483647 这组测试用例。离散后,映射关系 保存在字典中。从左往右遍历数组,先 query ,再 update ,这个顺序和第 327 题是反的。先 query 查找 `[2*nums[i] + 1, len(indexMap)-1]` 这个区间内满足条件的值,这个区间内的值都是 `> 2*nums[j]` 的。这一题移动的是 `j`,`j` 不断的变化,往线段树中不断插入的是 `i`。每轮循环先 query 一次前一轮循环中累积插入线段树中的 `i`,这些累积在线段树中的代表的是所有在 `j` 前面的 `i`。query 查询的是本轮 `[2*nums[j] + 1, len(indexMap)-1]`,如果能找到,即找到了这样一个 `j`,能满足 `nums[i] > 2*nums[j`, 把整个数组都扫完,累加的 query 出来的 count 计数就是最终答案。
41+
- 类似的题目:第 327 题,第 315 题。
42+
- 这一题用线段树并不是最优解,用线段树解这一题是为了训练线段树这个数据结构。最优解是解法二中的 mergesort。

0 commit comments

Comments
 (0)