Update solution 1649、493

This commit is contained in:
YDZ
2021-04-22 17:07:22 +08:00
parent e0aed6a035
commit d4d5a20eb1
10 changed files with 215 additions and 270 deletions

View File

@ -6,8 +6,69 @@ import (
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 线段树,时间复杂度 O(n log n)
// 解法一 归并排序 mergesort,时间复杂度 O(n log n)
func reversePairs(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
}
// 解法二 树状数组,时间复杂度 O(n log n)
func reversePairs1(nums []int) (cnt int) {
n := len(nums)
if n <= 1 {
return
}
// 离散化所有下面统计时会出现的元素
allNums := make([]int, 0, 2*n)
for _, v := range nums {
allNums = append(allNums, v, 2*v)
}
sort.Ints(allNums)
k := 1
kth := map[int]int{allNums[0]: k}
for i := 1; i < 2*n; i++ {
if allNums[i] != allNums[i-1] {
k++
kth[allNums[i]] = k
}
}
bit := template.BinaryIndexedTree{}
bit.Init(k)
for i, v := range nums {
cnt += i - bit.Query(kth[2*v])
bit.Add(kth[v], 1)
}
return
}
// 解法三 线段树,时间复杂度 O(n log n)
func reversePairs2(nums []int) int {
if len(nums) < 2 {
return 0
}
@ -42,35 +103,3 @@ func reversePairs(nums []int) int {
}
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

@ -31,6 +31,11 @@ func Test_Problem493(t *testing.T) {
ans493{2},
},
{
para493{[]int{9, 8, 7, 4, 7, 2, 3, 8, 7, 0}},
ans493{18},
},
{
para493{[]int{2, 4, 3, 5, 1}},
ans493{3},

View File

@ -38,5 +38,6 @@ You need to return the number of important reverse pairs in the given array.
- 给出一个数组,要求找出满足条件的所有的“重要的反转对” (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 计数就是最终答案。
- 另外一种解法是树状数组。树状数组最擅长解答逆序对的问题。先将原数组中所有的元素值的 2 倍算出来,和原数组合并到一个大数组中。这个大数组中装了所有可能产生 2 倍逆序对的元素值。然后再将他们所有值排序,离散化。离散化以后便将问题集转化成 `[1,N]` 这个区间。于是回到了树状数组经典的求逆序对的问题。逆序插入原数组构造树状数组,或者正序插入原数组构造树状数组都可以解答此题。
- 类似的题目:第 327 题,第 315 题。
- 这一题用线段树并不是最优解,用线段树解这一题是为了训练线段树个数据结构。最优解是解法中的 mergesort。
- 这一题用线段树和树状数组并不是最优解,用线段树和树状数组解这一题是为了训练线段树和树状数组这两个数据结构。最优解是解法中的 mergesort。

View File

@ -1,12 +1,26 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
"sort"
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 线段树 SegmentTree
// 解法一 树状数组 Binary Indexed Tree
func createSortedArray(instructions []int) int {
bit, res := template.BinaryIndexedTree{}, 0
bit.Init(100001)
for i, v := range instructions {
less := bit.Query(v - 1)
greater := i - bit.Query(v)
res = (res + min(less, greater)) % (1e9 + 7)
bit.Add(v, 1)
}
return res
}
// 解法二 线段树 SegmentTree
func createSortedArray1(instructions []int) int {
if len(instructions) == 0 {
return 0
}
@ -49,58 +63,3 @@ func min(a int, b int) int {
}
return a
}
// 解法二 树状数组 Binary Indexed Tree
func createSortedArray1(instructions []int) int {
b := newBIT(make([]int, 100001))
var res int
cnt := map[int]int{}
for i, n := range instructions {
less := b.get(n - 1)
greater := i - less - cnt[n]
res = (res + min(less, greater)) % (1e9 + 7)
b.update(n, 1)
cnt[n]++
}
return res % (1e9 + 7)
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
type BIT struct {
data []int
}
func newBIT(nums []int) *BIT {
data := make([]int, len(nums)+1)
b := &BIT{data}
for i, n := range nums {
b.update(i, n)
}
return b
}
func (b *BIT) update(i, num int) {
i++
for i < len(b.data) {
b.data[i] += num
i += (i & -i)
}
}
func (b *BIT) get(i int) int {
i++
var sum int
for i > 0 {
sum += b.data[i]
i -= (i & -i)
}
return sum
}

View File

@ -83,12 +83,26 @@ The total cost is 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 2 = 4.
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
"sort"
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 线段树 SegmentTree
// 解法一 树状数组 Binary Indexed Tree
func createSortedArray(instructions []int) int {
bit, res := template.BinaryIndexedTree{}, 0
bit.Init(100001)
for i, v := range instructions {
less := bit.Query(v - 1)
greater := i - bit.Query(v)
res = (res + min(less, greater)) % (1e9 + 7)
bit.Add(v, 1)
}
return res
}
// 解法二 线段树 SegmentTree
func createSortedArray1(instructions []int) int {
if len(instructions) == 0 {
return 0
}
@ -132,58 +146,4 @@ func min(a int, b int) int {
return a
}
// 解法二 树状数组 Binary Indexed Tree
func createSortedArray1(instructions []int) int {
b := newBIT(make([]int, 100001))
var res int
cnt := map[int]int{}
for i, n := range instructions {
less := b.get(n - 1)
greater := i - less - cnt[n]
res = (res + min(less, greater)) % (1e9 + 7)
b.update(n, 1)
cnt[n]++
}
return res % (1e9 + 7)
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
type BIT struct {
data []int
}
func newBIT(nums []int) *BIT {
data := make([]int, len(nums)+1)
b := &BIT{data}
for i, n := range nums {
b.update(i, n)
}
return b
}
func (b *BIT) update(i, num int) {
i++
for i < len(b.data) {
b.data[i] += num
i += (i & -i)
}
}
func (b *BIT) get(i int) int {
i++
var sum int
for i > 0 {
sum += b.data[i]
i -= (i & -i)
}
return sum
}
```

View File

@ -7,38 +7,37 @@ type BinaryIndexedTree struct {
}
// Init define
func (bit *BinaryIndexedTree) Init(nums []int, capacity int) {
if len(nums) == 0 {
bit.tree, bit.capacity = make([]int, capacity+1), capacity+1
return
}
bit.tree, bit.capacity = make([]int, len(nums)+1), len(nums)+1
for i := 1; i <= len(nums); i++ {
bit.tree[i] += nums[i-1]
for j := i - 2; j >= i-lowbit(i); j-- {
bit.tree[i] += nums[j]
}
}
func (bit *BinaryIndexedTree) Init(capacity int) {
bit.tree, bit.capacity = make([]int, capacity+1), capacity
}
// Add define
func (bit *BinaryIndexedTree) Add(index int, val int) {
for index <= bit.capacity {
for ; index <= bit.capacity; index += index & -index {
bit.tree[index] += val
index += lowbit(index)
}
}
// Query define
func (bit *BinaryIndexedTree) Query(index int) int {
sum := 0
for index >= 1 {
for ; index > 0; index -= index & -index {
sum += bit.tree[index]
index -= lowbit(index)
}
return sum
}
// InitWithNums define
func (bit *BinaryIndexedTree) InitWithNums(nums []int) {
bit.tree, bit.capacity = make([]int, len(nums)+1), len(nums)
for i := 1; i <= len(nums); i++ {
bit.tree[i] += nums[i-1]
for j := i - 2; j >= i-lowbit(i); j-- {
bit.tree[i] += nums[j]
}
}
}
func lowbit(x int) int {
return x & -x
}

View File

@ -7,6 +7,6 @@ import (
func Test_BIT(t *testing.T) {
nums, bit := []int{1, 2, 3, 4, 5, 6, 7, 8}, BinaryIndexedTree{}
bit.Init(nums, 8)
fmt.Printf("%v\n", bit.tree) // [0 1 3 3 10 5 11 7 36]
bit.Init(8)
fmt.Printf("nums = %v bit = %v\n", nums, bit.tree) // [0 1 3 3 10 5 11 7 36]
}

View File

@ -38,8 +38,9 @@ You need to return the number of important reverse pairs in the given array.
- 给出一个数组,要求找出满足条件的所有的“重要的反转对” (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 计数就是最终答案。
- 另外一种解法是树状数组。树状数组最擅长解答逆序对的问题。先将原数组中所有的元素值的 2 倍算出来,和原数组合并到一个大数组中。这个大数组中装了所有可能产生 2 倍逆序对的元素值。然后再将他们所有值排序,离散化。离散化以后便将问题集转化成 `[1,N]` 这个区间。于是回到了树状数组经典的求逆序对的问题。逆序插入原数组构造树状数组,或者正序插入原数组构造树状数组都可以解答此题。
- 类似的题目:第 327 题,第 315 题。
- 这一题用线段树并不是最优解,用线段树解这一题是为了训练线段树个数据结构。最优解是解法中的 mergesort。
- 这一题用线段树和树状数组并不是最优解,用线段树和树状数组解这一题是为了训练线段树和树状数组这两个数据结构。最优解是解法中的 mergesort。
## 代码
@ -54,8 +55,69 @@ import (
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 线段树,时间复杂度 O(n log n)
// 解法一 归并排序 mergesort,时间复杂度 O(n log n)
func reversePairs(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
}
// 解法二 树状数组,时间复杂度 O(n log n)
func reversePairs1(nums []int) (cnt int) {
n := len(nums)
if n <= 1 {
return
}
// 离散化所有下面统计时会出现的元素
allNums := make([]int, 0, 2*n)
for _, v := range nums {
allNums = append(allNums, v, 2*v)
}
sort.Ints(allNums)
k := 1
kth := map[int]int{allNums[0]: k}
for i := 1; i < 2*n; i++ {
if allNums[i] != allNums[i-1] {
k++
kth[allNums[i]] = k
}
}
bit := template.BinaryIndexedTree{}
bit.Init(k)
for i, v := range nums {
cnt += i - bit.Query(kth[2*v])
bit.Add(kth[v], 1)
}
return
}
// 解法三 线段树,时间复杂度 O(n log n)
func reversePairs2(nums []int) int {
if len(nums) < 2 {
return 0
}
@ -91,38 +153,6 @@ func reversePairs(nums []int) int {
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

@ -83,12 +83,26 @@ The total cost is 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 2 = 4.
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
"sort"
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 线段树 SegmentTree
// 解法一 树状数组 Binary Indexed Tree
func createSortedArray(instructions []int) int {
bit, res := template.BinaryIndexedTree{}, 0
bit.Init(100001)
for i, v := range instructions {
less := bit.Query(v - 1)
greater := i - bit.Query(v)
res = (res + min(less, greater)) % (1e9 + 7)
bit.Add(v, 1)
}
return res
}
// 解法二 线段树 SegmentTree
func createSortedArray1(instructions []int) int {
if len(instructions) == 0 {
return 0
}
@ -132,60 +146,6 @@ func min(a int, b int) int {
return a
}
// 解法二 树状数组 Binary Indexed Tree
func createSortedArray1(instructions []int) int {
b := newBIT(make([]int, 100001))
var res int
cnt := map[int]int{}
for i, n := range instructions {
less := b.get(n - 1)
greater := i - less - cnt[n]
res = (res + min(less, greater)) % (1e9 + 7)
b.update(n, 1)
cnt[n]++
}
return res % (1e9 + 7)
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
type BIT struct {
data []int
}
func newBIT(nums []int) *BIT {
data := make([]int, len(nums)+1)
b := &BIT{data}
for i, n := range nums {
b.update(i, n)
}
return b
}
func (b *BIT) update(i, num int) {
i++
for i < len(b.data) {
b.data[i] += num
i += (i & -i)
}
}
func (b *BIT) get(i int) int {
i++
var sum int
for i > 0 {
sum += b.data[i]
i -= (i & -i)
}
return sum
}
```

View File

@ -268,13 +268,14 @@ n 最多经过 {{< katex >}}(O(log n))^2 {{< /katex >}} 变化,最终 n < m。
再创建一个树状数组,用来记录这样一个数组 C下标从1算起的前缀和若 [1, N] 这个排列中的数 i 当前已经出现,则 C[i] 的值为 1 ,否则为 0。初始时数组 C 的值均为 0。从数组 B 第一个元素开始遍历,对树状数组执行修改数组 C 的第 B[j] 个数值加 1 的操作。再在树状数组中查询有多少个数小于等于当前的数 B[j](即用树状数组查询数组 C 中的 [1,B[j]] 区间前缀和),当前插入总数 i 减去小于等于 B[j] 元素总数,差值即为大于 B[j] 元素的个数,并加入计数器。
```go
func reversePair(s string) int {
s = "9854623870"
arr, newPermutation, bit, res := make([]Element, len(s)+1), make([]int, len(s)), BinaryIndexedTree{}, 0
bit.capacity = len(s)
for i := 0; i < len(s); i++ {
arr[i+1].data = int(s[i] - '0')
arr[i+1].pos = i + 1
func reversePairs(nums []int) int {
if len(nums) <= 1 {
return 0
}
arr, newPermutation, bit, res := make([]Element, len(nums)), make([]int, len(nums)), template.BinaryIndexedTree{}, 0
for i := 0; i < len(nums); i++ {
arr[i].data = nums[i]
arr[i].pos = i
}
sort.Slice(arr, func(i, j int) bool {
if arr[i].data == arr[j].data {
@ -286,19 +287,20 @@ func reversePair(s string) int {
}
return arr[i].data < arr[j].data
})
index := 1
newPermutation[arr[1].pos] = 1
for i := 2; i <= len(s); i++ {
id := 1
newPermutation[arr[0].pos] = 1
for i := 1; i < len(arr); i++ {
if arr[i].data == arr[i-1].data {
newPermutation[arr[i].pos] = index
newPermutation[arr[i].pos] = id
} else {
index++
newPermutation[arr[i].pos] = index
id++
newPermutation[arr[i].pos] = id
}
}
for i := 1; i < len(s); i++ {
bit.Init(id)
for i := 0; i < len(newPermutation); i++ {
bit.Add(newPermutation[i], 1)
res += i - bit.Query(newPermutation[i])
res += (i + 1) - bit.Query(newPermutation[i])
}
return res
}