1409. 查询带键的排列

75 阅读1分钟

题目:
给你一个待查数组 queries ,数组中的元素为 1m 之间的正整数。 请你根据以下规则处理所有待查项 queries[i](从 i=0i=queries.length-1):

  • 一开始,排列 P=[1,2,3,...,m]
  • 对于当前的 i ,请你找出待查项 queries[i] 在排列 P 中的位置(下标从 0 开始),然后将其从原位置移动到排列 P 的起始位置(即下标为 0 处)。注意, queries[i]P 中的位置就是 queries[i] 的查询结果。

请你以数组形式返回待查数组  queries 的查询结果。

算法:
方法一:树状数组
构造树状数组BIT 0|[1,n]|[n+1, m]。 初始状态,1~m填充在BIT[n+1, m]区间,每次查询一个数,将该数移动到BIT[1,n]区间内。查询n次共移动n次。所求ans[i]即i左侧有多少个数字。
另外需要用一个数组pos,维护qureies[i]在BIT中的位置。

func processQueries(queries []int, m int) []int {
    n := len(queries)
    BIT = make([]int, m + n + 1)
    ans := make([]int, n)
    // pos[val]=index, 维护[1,m]的元素val在BIT数组中的index
    pos := make([]int, m + 1)
    for i := 1; i <= m; i ++ {
        pos[i] = n + i
        add(n + i, 1)
    }
    for i := 0; i < n; i ++ {
        // queries[i] -> val -> BIT的index
        index := pos[queries[i]]
        // ans[i] = get[index]
        ans[i] = get(index - 1)
        // update(index, - 1)
        add(index, -1)
        // 更新pos
        index = n - i
        pos[queries[i]] = index
        // update(index2, 1)
        add(index, 1)
    }
    return ans
}

var BIT []int

func get(i int) int {
    ans := 0
    for i > 0 {
        ans = ans + BIT[i]
        i = i - lowBit(i)
    }
    return ans
}

func lowBit(x int) int {
    return x & (-x)
}

func add(i, v int) {
    for i < len(BIT) {
        BIT[i] = BIT[i] + v
        i = i + lowBit(i)
    }
}