添加 problem 493

This commit is contained in:
YDZ
2019-09-17 11:11:12 +08:00
parent 8f65cf9007
commit d3451441b4
3 changed files with 175 additions and 0 deletions

View File

@ -0,0 +1,76 @@
package leetcode
import (
"sort"
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 线段树,时间复杂度 O(n log n)
func reversePairs(nums []int) int {
if len(nums) < 2 {
return 0
}
st, numsMap, indexMap, numsArray, res := template.SegmentCountTree{}, make(map[int]int, 0), make(map[int]int, 0), []int{}, 0
numsMap[nums[0]] = nums[0]
for _, num := range nums {
numsMap[num] = num
numsMap[2*num+1] = 2*num + 1
}
// numsArray 是 prefixSum 去重之后的版本,利用 numsMap 去重
for _, v := range numsMap {
numsArray = append(numsArray, v)
}
// 排序是为了使得线段树中的区间 left <= right如果此处不排序线段树中的区间有很多不合法。
sort.Ints(numsArray)
// 离散化,构建映射关系
for i, n := range numsArray {
indexMap[n] = i
}
numsArray = []int{}
// 离散化此题如果不离散化MaxInt32 的数据会使得数字越界。
for i := 0; i < len(indexMap); i++ {
numsArray = append(numsArray, i)
}
// 初始化线段树,节点内的值都赋值为 0即计数为 0
st.Init(numsArray, func(i, j int) int {
return 0
})
for _, num := range nums {
res += st.Query(indexMap[num*2+1], len(indexMap)-1)
st.UpdateCount(indexMap[num])
}
return res
}
// 解法二 mergesort
func reversePairs1(nums []int) int {
buf := make([]int, len(nums))
return mergesortCount(nums, buf)
}
func mergesortCount(nums, buf []int) int {
if len(nums) <= 1 {
return 0
}
mid := (len(nums) - 1) / 2
cnt := mergesortCount(nums[:mid+1], buf)
cnt += mergesortCount(nums[mid+1:], buf)
for i, j := 0, mid+1; i < mid+1; i++ { // Note!!! j is increasing.
for ; j < len(nums) && nums[i] <= 2*nums[j]; j++ {
}
cnt += len(nums) - j
}
copy(buf, nums)
for i, j, k := 0, mid+1, 0; k < len(nums); {
if j >= len(nums) || i < mid+1 && buf[i] > buf[j] {
nums[k] = buf[i]
i++
} else {
nums[k] = buf[j]
j++
}
k++
}
return cnt
}

View File

@ -0,0 +1,57 @@
package leetcode
import (
"fmt"
"testing"
)
type question493 struct {
para493
ans493
}
// para 是参数
// one 代表第一个参数
type para493 struct {
nums []int
}
// ans 是答案
// one 代表第一个答案
type ans493 struct {
one int
}
func Test_Problem493(t *testing.T) {
qs := []question493{
question493{
para493{[]int{1, 3, 2, 3, 1}},
ans493{2},
},
question493{
para493{[]int{2, 4, 3, 5, 1}},
ans493{3},
},
question493{
para493{[]int{-5, -5}},
ans493{1},
},
question493{
para493{[]int{2147483647, 2147483647, -2147483647, -2147483647, -2147483647, 2147483647}},
ans493{9},
},
}
fmt.Printf("------------------------Leetcode Problem 493------------------------\n")
for _, q := range qs {
_, p := q.ans493, q.para493
fmt.Printf("【input】:%v 【output】:%v\n", p, reversePairs(p.nums))
}
fmt.Printf("\n\n\n")
}

View File

@ -0,0 +1,42 @@
# [493. Reverse Pairs](https://leetcode.com/problems/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.
## 题目大意
给定一个数组 nums 如果 i < j  nums[i] > 2\*nums[j] 我们就将 (i, j) 称作一个重要翻转对。你需要返回给定数组中的重要翻转对的数量。
注意:
- 给定数组的长度不会超过 50000。
- 输入数组中的所有数字都在 32 位整数的表示范围内。
## 解题思路
- 给出一个数组,要求找出满足条件的所有的“重要的反转对” (i,j)。重要的反转对的定义是:`i<j`,并且 `nums[i] > 2*nums[j]`
- 这一题是 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 计数就是最终答案。
- 类似的题目:第 327 题,第 315 题。
- 这一题用线段树并不是最优解,用线段树解这一题是为了训练线段树这个数据结构。最优解是解法二中的 mergesort。