LeetCode Biweekly Competition 103 (2023/04/29) The classic application of the tree array of interval summation

This article has included AndroidFamily , technical and workplace issues, please pay attention to the public account [Peng Xurui] to ask questions.

Hello everyone, I am Xiao Peng.

This weekly competition is the 103rd LeetCode biweekly competition. It is rare that the number of people playing the weekly competition on the first day of the May Day holiday is not too small. The first three questions in this competition are relatively simple, and we will save space for the last question.

Review of previous weekly competitions: LeetCode Single Weekly Competition No. 342 Principle of tolerance and exclusion, counting sort, sliding window, sub-array GCB

Weekly Tournament Overview

Q1. Maximum sum of K elements (Easy)

Simple simulation questions, but not too much explanation.

Q2. Find the prefix common array of two arrays (Medium)

Simple imitation question, there are three solutions in the implementation of counting:

  • Solution 1: Hashtable O ( n ) O(n)O ( n ) space complexity
  • Solution 2: array of tricks O ( n ) O(n)O ( n ) space complexity
  • Solution 3: State compression O ( 1 ) O(1)O ( 1 ) space complexity

Q3. The maximum number of fish in the grid graph (Hard)

Is the difficulty label on this question serious? Playing Medium is too much, but playing Hard?

  • Solution 1: BFS / DFS O ( nm ) O(nm)O ( nm )
  • Solution 2: Union search O ( nm ) O(nm)O ( nm )

Q4. Clear the array (Hard)

The difficulty of this question lies in how to think of and correctly convert the original problem into an interval summation problem. After thinking clearly, it can be realized with a tree array.

  • Solution 1: tree array + index array O ( nlgn ) O(nlgn)O ( n l g n )
  • Solution 2: tree array + minimum heap O ( nlgn ) O(nlgn)O ( n l g n )


Q1. Maximum sum of K elements (Easy)

https://leetcode.cn/problems/maximum-sum-with-exactly-k-elements/

topic description

You are given an   array of integers  indexed from 0nums  and an integer  k . You need to do the following  exactly k  times to maximize your score:

  1. nums Select an element from it  m .
  2. Remove selected elements  m from the array.
  3. Add new elements  m + 1 to the array.
  4. Your score increases  m .

Please return  k the maximum score after performing the above operations exactly times.

Example 1:

输入:nums = [1,2,3,4,5], k = 3
输出:18
解释:我们需要从 nums 中恰好选择 3 个元素并最大化得分。
第一次选择 5 。和为 5 ,nums = [1,2,3,4,6] 。
第二次选择 6 。和为 6 ,nums = [1,2,3,4,7] 。
第三次选择 7 。和为 5 + 6 + 7 = 18 ,nums = [1,2,3,4,8] 。
所以我们返回 18 。
18 是可以得到的最大答案。

Example 2:

输入:nums = [5,5,5], k = 2
输出:11
解释:我们需要从 nums 中恰好选择 2 个元素并最大化得分。
第一次选择 5 。和为 5 ,nums = [5,5,6] 。
第二次选择 6 。和为 6 ,nums = [5,5,7] 。
所以我们返回 11 。
11 是可以得到的最大答案。

hint:

  • 1 <= nums.length <= 100
  • 1 <= nums[i] <= 100
  • 1 <= k <= 100

Preliminary Knowledge - Sum of Arithmetic Sequences

  • Arithmetic series summation formula: (first item + last item) * number of items / 2

Solution (simulation + greedy)

Obviously, the score of the first operation will select the maximum value max in the array, and the subsequent operation is an arithmetic sequence with max as the first item, directly using the arithmetic sequence summation formula.

class Solution {
    
    
    fun maximizeSum(nums: IntArray, k: Int): Int {
    
    
        val max = Arrays.stream(nums).max().getAsInt()
        return (max + max + k - 1) * k / 2
    }
}

Complexity analysis:

  • Time complexity: O ( n ) O(n)O ( n ) where n is the length of the nums array;
  • Space complexity: O ( 1 ) O(1)O(1)

Q2. Find the prefix common array of two arrays (Medium)

https://leetcode.cn/problems/find-the-prefix-common-array-of-two-arrays/

topic description

You are given the sum of two permutations   of integers with subscripts  starting at 0  and   length   .nAB

AB A prefix of   and  common array  is defined as an array  C , where  C[i] is  the number of common elements before the array sum A to  B subscript  i .

Please return  A and  B prefix  the public array  .

n An array  of length  is said to be a  permutation  of  length if  it 1 contains  elements exactly once  .nn

Example 1:

输入:A = [1,3,2,4], B = [3,1,2,4]
输出:[0,2,3,4]
解释:i = 0:没有公共元素,所以 C[0] = 0 。
i = 1:1 和 3 是两个数组的前缀公共元素,所以 C[1] = 2 。
i = 2:1,2 和 3 是两个数组的前缀公共元素,所以 C[2] = 3 。
i = 3:1,2,3 和 4 是两个数组的前缀公共元素,所以 C[3] = 4 。

Example 2:

输入:A = [2,3,1], B = [3,1,2]
输出:[0,1,3]
解释:i = 0:没有公共元素,所以 C[0] = 0 。
i = 1:只有 3 是公共元素,所以 C[1] = 1 。
i = 2:1,2 和 3 是两个数组的前缀公共元素,所以 C[2] = 3 。

hint:

  • 1 <= A.length == B.length == n <= 50
  • 1 <= A[i], B[i] <= n
  • The title guarantees  A that  B both arrays are  n arrays of elements.

Solution 1 (hash table)

Traverse the array from left to right, and use the hash table to record the elements visited, and the intersection of the two arrays:

class Solution {
    
    
    fun findThePrefixCommonArray(A: IntArray, B: IntArray): IntArray {
    
    
        val n = A.size
        val ret = IntArray(n)
        val setA = HashSet<Int>()
        val setB = HashSet<Int>()
        val interSet = HashSet<Int>()
        for (i in 0 until n) {
    
    
            setA.add(A[i])
            setB.add(B[i])
            if (setB.contains(A[i])) interSet.add(A[i])
            if (setA.contains(B[i])) interSet.add(B[i])
            ret[i] = interSet.size
        }
        return ret
    }
}

Complexity analysis:

  • Time complexity: O ( n ) O(n)O ( n ) where n is the length of the nums array;
  • Space Complexity: O ( n ) O(n)O ( n ) hash table space.

Solution 2 (counting arrays)

Solution 1 needs to use multiple spaces. We found that both A and B are permutations of n. When the accessed element nums[i] appears twice, it must be in the intersection of the arrays. Therefore, instead of using a hash table to record the visited elements, we only need to record the number of occurrences of each element.

class Solution {
    
    
    fun findThePrefixCommonArray(A: IntArray, B: IntArray): IntArray {
    
    
        val n = A.size
        val ret = IntArray(n)
        val cnt = IntArray(n + 1)
        var size = 0
        for (i in 0 until n) {
    
    
            if (++cnt[A[i]] == 2) size ++
            if (++cnt[B[i]] == 2) size ++
            ret[i] = size
        }
        return ret
    }
}

Complexity analysis:

  • Time complexity: O ( n ) O(n)O ( n ) where n is the length of the nums array;
  • Space Complexity: O ( n ) O(n)O ( n ) count array space;

Solution 3 (state compression)

Since the element values ​​of A and B do not exceed 50, we can use two Long variables instead of a hash table to optimize the space complexity.

class Solution {
    
    
    fun findThePrefixCommonArray(A: IntArray, B: IntArray): IntArray {
    
    
        val n = A.size
        val ret = IntArray(n)
        var flagA = 0L
        var flagB = 0L
        var size = 0
        for (i in 0 until n) {
    
    
            flagA = flagA or (1L shl A[i])
            flagB = flagB or (1L shl B[i])
            // Kotlin 1.5 才有 Long.countOneBits()
            // ret[i] = (flagA and flagB).countOneBits()
            ret[i] = java.lang.Long.bitCount(flagA and flagB)
        }
        return ret
    }
}

Complexity analysis:

  • Time complexity: O ( n ) O(n)O ( n ) where n is the length of the nums array;
  • Space complexity: O ( 1 ) O(1)O ( 1 ) uses only constant level space;

Q3. The maximum number of fish in the grid graph (Hard)

https://leetcode.cn/problems/maximum-number-of-fish-in-a-grid/description/

topic description

Given a   two-dimensional array of integers   with subscripts starting  from 0  , where the integers at subscripts   represent:m x ngrid(r, c)

  • If  grid[r][c] = 0 , then it is a piece  of land  .
  • If  grid[r][c] > 0 , then it is a  body of water  and contains  grid[r][c] a fish.

A fisherman can start from any  water  tile  (r, c) , and then perform the following operations any number of times:

  • Catch  (r, c) all the fish in the grid, or
  • Move to adjacent  water  tile.

Please return to the fisherman's optimal strategy,  how many fish can be caught at most  . If there is no water grid, please return  0 .

(r, c) The adjacent grids of the grid   are  (r, c + 1) , (r, c - 1) , (r + 1, c) and  (r - 1, c) , provided that the adjacent grids are in the grid diagram.

Example 1:

输入:grid = [[0,2,1,0],[4,0,0,3],[1,0,0,4],[0,3,2,0]]
输出:7
解释:渔夫可以从格子(1,3) 出发,捕捞 3 条鱼,然后移动到格子(2,3) ,捕捞 4 条鱼。

Example 2:

输入:grid = [[1,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]]
输出:1
解释:渔夫可以从格子 (0,0) 或者 (3,3) ,捕捞 1 条鱼。

hint:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 10
  • 0 <= grid[i][j] <= 10

problem abstraction

To find the "weighted connected component/island problem", the maximum value of all connected blocks can be found by using two-dimensional BFS or DFS or union search, which is the most watery Hard problem in history.

Solution 1 (two-dimensional DFS)

class Solution {
    
    

    private val directions = arrayOf(intArrayOf(0, 1), intArrayOf(0, -1), intArrayOf(1, 0), intArrayOf(-1, 0))

    fun findMaxFish(grid: Array<IntArray>): Int {
    
    
        var ret = 0
        for (i in 0 until grid.size) {
    
    
            for (j in 0 until grid[0].size) {
    
    
                ret = Math.max(ret, dfs(grid, i, j))
            }
        }
        return ret
    }

    private fun dfs(grid: Array<IntArray>, i: Int, j: Int): Int {
    
    
        if (grid[i][j] <= 0) return 0
        var cur = grid[i][j]
        grid[i][j] = -1
        for (direction in directions) {
    
    
            val newI = i + direction[0]
            val newJ = j + direction[1]
            if (newI < 0 || newI >= grid.size || newJ < 0 || newJ >= grid[0].size || grid[newI][newJ] <= 0) continue
            cur += dfs(grid, newI, newJ)
        }
        return cur
    }
}

Complexity analysis:

  • Time complexity: O ( n ⋅ m ) O(n m)O(nm ) where n and m are the rows and columns of the grid array;
  • Space complexity: O ( n + m ) O(n + m)O ( n+m ) The maximum depth of the recursive stack.

Solution 2 (and check set)

Attached is a solution to find and collect:

class Solution {
    
    

    private val directions = arrayOf(intArrayOf(0, 1), intArrayOf(0, -1), intArrayOf(1, 0), intArrayOf(-1, 0))

    fun findMaxFish(grid: Array<IntArray>): Int {
    
    
        val n = grid.size
        val m = grid[0].size
        var ret = 0
        // 并查集
        val helper = UnionFind(grid)
        // 合并
        for (i in 0 until n) {
    
    
            for (j in 0 until m) {
    
    
                ret = Math.max(ret, grid[i][j])
                if (grid[i][j] <= 0) continue
                for (direction in directions) {
    
    
                    val newI = i + direction[0]
                    val newJ = j + direction[1]
                    if (newI < 0 || newI >= grid.size || newJ < 0 || newJ >= grid[0].size || grid[newI][newJ] <= 0) continue
                    ret = Math.max(ret, helper.union(i * m + j, newI * m + newJ))
                }
            }
        }
        // helper.print()
        return ret
    }

    private class UnionFind(private val grid: Array<IntArray>) {
    
    

        private val n = grid.size
        private val m = grid[0].size

        // 父节点
        private val parent = IntArray(n * m) {
    
     it }
        // 高度
        private val rank = IntArray(n * m)
        // 数值
        private val value = IntArray(n * m)

        init {
    
    
            for (i in 0 until n) {
    
    
                for (j in 0 until m) {
    
    
                    value[i * m + j] = grid[i][j]
                }
            }
        }

        // return 子集的和
        fun union(x: Int, y: Int): Int {
    
    
            // 按秩合并
            val parentX = find(x)
            val parentY = find(y)
            if (parentX == parentY) return value[parentY]
            if (rank[parentX] < rank[parentY]) {
    
    
                parent[parentX] = parentY
                value[parentY] += value[parentX]
                return value[parentY]
            } else if (rank[parentY] < rank[parentX]) {
    
    
                parent[parentY] = parentX
                value[parentX] += value[parentY]
                return value[parentX]
            } else {
    
    
                parent[parentY] = parentX
                value[parentX] += value[parentY]
                rank[parentY]++
                return value[parentX]
            }
        }

        fun print() {
    
    
            println("parent=${
      
      parent.joinToString()}")
            println("rank=${
      
      rank.joinToString()}")
            println("value=${
      
      value.joinToString()}")
        }

        private fun find(i: Int): Int {
    
    
            // 路径压缩
            var x = i
            while (parent[x] != x) {
    
    
                parent[x] = parent[parent[x]]
                x = parent[x]
            }
            return x
        }
    }
}

Complexity analysis:

  • Time complexity: O ( n ⋅ m ) O(n m)O(nm ) where n and m are the rows and columns of the grid array;
  • Space complexity: O ( n + m ) O(n + m)O ( n+m ) The maximum depth of the recursive stack.

Similar topics:

Recommended reading:


Q4. Clear the array (Hard)

https://leetcode.cn/problems/make-array-empty/

topic description

Given an  array of distinct  integers  nums , you need to do the following  until the array is empty  :

  • If the first element in the array is the smallest value in the current array   , delete it.
  • Otherwise, move the first element to  the end of the array  .

Please return how many operations are needed to make  nums empty.

Example 1:

输入:nums = [3,4,-1]
输出:5
Operation Array
1 [4, -1, 3]
2 [-1, 3, 4]
3 [3, 4]
4 [4]
5 []

Example 2:

输入:nums = [1,2,4,3]
输出:5
Operation Array
1 [2, 4, 3]
2 [4, 3]
3 [3, 4]
4 [4]
5 []

Example 3:

输入:nums = [1,2,3]
输出:3
Operation Array
1 [2, 3]
2 [3]
3 []

hint:

  • 1 <= nums.length <= 105
  • 109 <= nums[i] <= 109
  • nums The elements in  are different from each other  .

Preliminary Knowledge - Looping Arrays

Circular array: The successor of the element at the end of the array is regarded as the element at the head of the array, and the predecessor of the element at the head of the array is regarded as the element at the end of the array.

Preliminary knowledge - tree array

OI tree array

A tree array is also called a Binary Indexed Tree (Binary Indexed Tree), which is a data structure that supports "single-point modification" and "interval query" with a small amount of code. Compared with the line segment tree, the code amount of the tree array is far less, and it is an exquisite data structure.

The core idea of ​​the tree array is to split the prefix sum of the array [0,x] into non-overlapping intervals of no more than logx segments. When calculating the prefix sum, only the interval information of the logx segment needs to be merged, instead of n interval information. . At the same time, when updating a single-point value, only the logx segment interval needs to be modified, and there is no need to modify n pieces of information like prefixes and arrays. It can be said that the tree array balances the time complexity of single-point modification and interval and query:

  • Single-point update add(index,val): Add val to the index element of the sequence, the time complexity is O(lgn), and it corresponds to the process of moving from small block nodes to large block nodes on the logical tree structure (modify element will affect the value of the large block node (child node));
  • Interval query prefixSum(index): Query the prefix sum of the first index elements, the time complexity is O(lgn), and it corresponds to the process of accumulating interval segments on the logical tree structure.

树状数组

problem structuring

1. Summarize the problem goal

Find the number of operations to eliminate an array.

2. Analyze the key elements of the topic

  • Observation: In each operation, it is necessary to observe whether the first element of the array is the minimum value among the remaining elements. For example, the first element of the sequence [3,2,1] is not the minimum value;
  • Elimination: In each operation, if the first element of the array is the minimum value, the first element of the array can be eliminated. Example sequence [1,2,3] becomes [2,3] after one operation;
  • Move: In each operation, if the first element of the array is not the minimum value, it needs to be moved to the end of the array. For example the sequence [3,2,1] becomes [2,1,3] after one operation.

3. Observe the characteristics of the data

  • Data volume: The upper bound of the data volume of the test case is 10^5, which requires us to implement an algorithm with a time complexity lower than O(n^2) to pass;
  • Data size: The upper and lower bounds of the test case data are [-10^9, 10^9], which requires us to consider large numbers.

4. Observe the test cases

Take the sequence [3,4,-1] as an example, a total of 5 operations:

  • [3,4,-1]: -1 is the minimum value, and -1 can only be eliminated after moving 3 and 4 to the end, a total of 3 operations;
  • [3,4]: 3 is the minimum value, eliminate 3 operation 1 time;
  • [4]: 4 is the minimum value, remove 4 and operate 1 time;

5. Increase the level of abstraction

  • Sequence: A linear list is a sequence composed of multiple elements, each element has a predecessor element and a successor element except the head and tail elements of the array. When moving the first element of the array to the end of the array, the relationship of some elements in the array will be changed, that is, the predecessor of the original first element becomes the original tail element, and the successor of the original tail element becomes the original first element.
  • Whether it is a decision-making problem: Since the behavior of each operation is fixed, this question is only a purely simulation problem, not a decision-making problem.

6. Specific solutions

The elimination operation needs to delete the element values ​​in ascending order, so how to judge whether the first element of the array is the minimum value?

  • Method 1 (violent enumeration): Enumerate the remaining elements of the array and judge whether the first element is the minimum value. The time complexity of a single judgment is O(n);
  • Method 2 (Sorting): Preprocess and sort the original array. Since the element order information of the original array is crucial in this problem, the original array cannot be sorted in situ. Auxiliary data structures, such as index arrays, are needed , Minimum heap, the amortized time complexity of a single judgment is O(1).

How to represent the move operation of an element:

  • Method 1 (Array): Use Arrays.copy() to copy Arrays in blocks, and the time complexity of a single operation is O(n);
  • Method 2 (doubly linked list): convert the original array into a doubly linked list, the time complexity of operating the first and last elements of the linked list is O(1), but it will consume more space;

How to solve the problem:

  • Means 1 (simulation): Simulate the eliminate and move operations until the array is empty. In the worst case (descending array), it needs to operate n^2 times, so it cannot meet the data volume requirements of the topic anyway;

So far, the problem has reached a bottleneck.

The solution is to repeat the process of "analyzing the elements of the problem" - "concrete solutions", and enumerate the mastered algorithms, data structures and tricks to find breakthroughs:

New means of representing movement operations on elements:

  • Method 3 (circular array): treat the original array as a circular array, the successor of the tail element of the array is the first element of the array, and the predecessor of the first element of the array is the tail element of the array, no actual moving operation is required.

New means of solving problems:

  • Means 2 (counting): Observe the test case and find that the number of operations to eliminate each element depends on the number of uneliminated elements in the predecessor of the element, for example, there are 2 before -1 in the sequence [3,4,-1] Elements are not removed, so 2 operations are needed to move 3 and 4, and one more operation to remove -1. Then, we can define rangeSum(i,j) to represent the number of undeleted elements in the interval [i,j]. Each elimination operation only needs to query the last elimination position (the last minimum value) and the current elimination position (Current minimum value) How many numbers in the middle have not been eliminated rangeSum (previous minimum value position, current minimum value position), the sum of this interval is the number of operations required to eliminate the current element.

Distinguishing the relationship between the last position and the current position requires classification and discussion:

  • id < preId: times of elimination = rangeSum(id, preId)
  • id > preId: times of elimination = rangeSum(-1, id) + rangeSum(preId,n - 1)

How to implement means 2 (count):

In terms of code implementation, the "interval summation" and "single point update" can be implemented with the number of line segments and tree arrays. The code size of the tree array is much less than that of the line segment tree, so we choose the latter.

示意图

Q&A:

  • Does the number of operations to eliminate each element not consider elements in the predecessor element that are smaller than the current element?

Since the elimination is performed in ascending order of element values, the uneliminated elements must be larger than the current element, so we do not emphasize the element size relationship.

Solution 1 (tree array + index array)

  • Use the method of "tree array" to solve the problem of interval and query and single-point update. Note that the tree array is base 1;
  • Use "indexed array" means to solve sorting/minimum problems.
class Solution {
    
    
    fun countOperationsToEmptyArray(nums: IntArray): Long {
    
    
        val n = nums.size
        var ret = 0L
        // 索引数组
        val ids = Array<Int>(n) {
    
     it }
        // 排序
        Arrays.sort(ids) {
    
     i1, i2 ->
            // 考虑大数问题
            // nums[i1] - nums[i2] x
            if (nums[i1] < nums[i2]) -1 else 1
        }
        // 树状数组
        val bst = BST(n)
        // 上一个被删除的索引
        var preId = -1
        // 遍历索引
        for (id in ids) {
    
    
            // 区间和
            if (id > preId) {
    
    
                ret += bst.rangeSum(preId, id)
                // println("id=$id, ${bst.rangeSum(preId, id)}")
            } else {
    
    
                ret += bst.rangeSum(-1, id) + bst.rangeSum(preId, n - 1)
                // println("id=$id, ${bst.rangeSum(-1,id)} + ${bst.rangeSum(preId, n - 1)}")
            }
            // 单点更新
            bst.dec(id)
            preId = id
        }
        return ret
    }

    // 树状数组
    private class BST(private val n: Int) {
    
    

        // base 1
        private val data = IntArray(n + 1)

        init {
    
    
            // O(nlgn) 建树
            // for (i in 0 .. n) {
    
    
            //     update(i, 1)
            // }
            // O(n) 建树
            for (i in 1 .. n) {
    
    
                data[i] += 1
                val parent = i + lowbit(i)
                if (parent <= n) data[parent] += data[i]
            }
        }

        fun rangeSum(i1: Int, i2: Int): Int {
    
    
            return preSum(i2 + 1) - preSum(i1 + 1)
        }

        fun dec(i: Int) {
    
    
            update(i + 1, -1)
        }

        private fun preSum(i: Int): Int {
    
    
            var x = i
            var sum = 0
            while (x > 0) {
    
    
                sum += data[x]
                x -= lowbit(x)
            }
            return sum
        }

        private fun update(i: Int, delta: Int) {
    
    
            var x = i
            while (x <= n) {
    
    
                data[x] += delta
                x += lowbit(x)
            }
        }

        private fun lowbit(x: Int) = x and (-x)
    }
}

Complexity analysis:

  • Time complexity: O ( nlgn ) O(nlgn)O ( n l g n ) where n is the length of the nums array, sortingO(nlgn) O(nlgn)O ( n l g n ) , tree array buildingO ( n ) O(n)O ( n ) , interval and query for single elimination operation and time for single point update isO(lgn) O(lgn)O ( lgn ) _ _
  • Space Complexity: O ( n ) O(n)O ( n ) index array space + tree array space.

Solution 2 (tree array + minimum heap)

Attached is a minimal heap sorting code:

  • Use the method of "tree array" to solve the problem of interval and query and single-point update. Note that the tree array is base 1;
  • Use the "min heap" approach to solve sorting/minimum problems.
class Solution {
    
    
    fun countOperationsToEmptyArray(nums: IntArray): Long {
    
    
        val n = nums.size
        var ret = 0L
        // 最小堆
        val ids = PriorityQueue<Int>() {
    
     i1, i2 ->
            if (nums[i1] < nums[i2]) -1 else 1
        }
        for (id in 0 until n) {
    
    
            ids.offer(id)
        }
        // 树状数组
        val bst = BST(n)
        // 上一个被删除的索引
        var preId = -1
        // 遍历索引
        while (!ids.isEmpty()) {
    
    
            val id = ids.poll()
            // 区间和
            if (id > preId) {
    
    
                ret += bst.rangeSum(preId, id)
            } else {
    
    
                ret += bst.rangeSum(-1, id) + bst.rangeSum(preId, n - 1)
            }
            // 单点更新
            bst.dec(id)
            preId = id
        }
        return ret
    }
}

Complexity analysis:

  • Time complexity: O ( nlgn ) O(nlgn)O ( n l g n ) where n is the length of the nums array, heap sortO ( nlgn ) O(nlgn)O ( n l g n ) , tree array buildingO ( n ) O(n)O ( n ) , interval and query for single elimination operation and time for single point update isO(lgn) O(lgn)O ( lgn ) _ _
  • Space Complexity: O ( n ) O(n)O ( n ) heap space + tree array space.

Similar topics:


Past review

Guess you like

Origin blog.csdn.net/pengxurui/article/details/130487702