diff --git a/leetcode/0493.Reverse-Pairs/493. Reverse Pairs.go b/leetcode/0493.Reverse-Pairs/493. Reverse Pairs.go index b21a85a5..ec312a33 100644 --- a/leetcode/0493.Reverse-Pairs/493. Reverse Pairs.go +++ b/leetcode/0493.Reverse-Pairs/493. Reverse Pairs.go @@ -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 -} diff --git a/leetcode/0493.Reverse-Pairs/493. Reverse Pairs_test.go b/leetcode/0493.Reverse-Pairs/493. Reverse Pairs_test.go index 49ff2de2..2c909708 100644 --- a/leetcode/0493.Reverse-Pairs/493. Reverse Pairs_test.go +++ b/leetcode/0493.Reverse-Pairs/493. Reverse Pairs_test.go @@ -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}, diff --git a/leetcode/0493.Reverse-Pairs/README.md b/leetcode/0493.Reverse-Pairs/README.md index 2094a361..c2768919 100755 --- a/leetcode/0493.Reverse-Pairs/README.md +++ b/leetcode/0493.Reverse-Pairs/README.md @@ -38,5 +38,6 @@ You need to return the number of important reverse pairs in the given array. - 给出一个数组,要求找出满足条件的所有的“重要的反转对” (i,j)。重要的反转对的定义是:`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。 diff --git a/leetcode/1649.Create-Sorted-Array-through-Instructions/1649. Create Sorted Array through Instructions.go b/leetcode/1649.Create-Sorted-Array-through-Instructions/1649. Create Sorted Array through Instructions.go index c60b1836..094f4cd0 100644 --- a/leetcode/1649.Create-Sorted-Array-through-Instructions/1649. Create Sorted Array through Instructions.go +++ b/leetcode/1649.Create-Sorted-Array-through-Instructions/1649. Create Sorted Array through Instructions.go @@ -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 -} diff --git a/leetcode/1649.Create-Sorted-Array-through-Instructions/README.md b/leetcode/1649.Create-Sorted-Array-through-Instructions/README.md index 2f99c307..0ecda999 100644 --- a/leetcode/1649.Create-Sorted-Array-through-Instructions/README.md +++ b/leetcode/1649.Create-Sorted-Array-through-Instructions/README.md @@ -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 -} ``` \ No newline at end of file diff --git a/template/BIT.go b/template/BIT.go index 57d88068..0679b426 100644 --- a/template/BIT.go +++ b/template/BIT.go @@ -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 } diff --git a/template/BIT_test.go b/template/BIT_test.go index 4ec5786f..062cae72 100644 --- a/template/BIT_test.go +++ b/template/BIT_test.go @@ -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] } diff --git a/website/content/ChapterFour/0400~0499/0493.Reverse-Pairs.md b/website/content/ChapterFour/0400~0499/0493.Reverse-Pairs.md index d307f2b6..14256f76 100755 --- a/website/content/ChapterFour/0400~0499/0493.Reverse-Pairs.md +++ b/website/content/ChapterFour/0400~0499/0493.Reverse-Pairs.md @@ -38,8 +38,9 @@ You need to return the number of important reverse pairs in the given array. - 给出一个数组,要求找出满足条件的所有的“重要的反转对” (i,j)。重要的反转对的定义是:`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 -} - ``` diff --git a/website/content/ChapterFour/1600~1699/1649.Create-Sorted-Array-through-Instructions.md b/website/content/ChapterFour/1600~1699/1649.Create-Sorted-Array-through-Instructions.md index 63f7c120..fa098714 100644 --- a/website/content/ChapterFour/1600~1699/1649.Create-Sorted-Array-through-Instructions.md +++ b/website/content/ChapterFour/1600~1699/1649.Create-Sorted-Array-through-Instructions.md @@ -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 -} ``` diff --git a/website/content/ChapterThree/Binary_Indexed_Tree.md b/website/content/ChapterThree/Binary_Indexed_Tree.md index 18dcb868..d605e30d 100644 --- a/website/content/ChapterThree/Binary_Indexed_Tree.md +++ b/website/content/ChapterThree/Binary_Indexed_Tree.md @@ -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 }