解法一:模拟
记录每个数的下标位置,每次查询直接给出结果,然后更新下标数组:比该位置小的都加1,该位置的值更新为0。
时间复杂度:
class Solution {public int[] processQueries(int[] queries, int m) {int[] index = new int[m + 1];for (int i = 1; i <= m; ++i) {index[i] = i - 1;}int[] ans = new int[queries.length];for (int i = 0; i < queries.length; ++i) {ans[i] = index[queries[i]];for (int j = 1; j <= m; ++j) {if (index[j] < ans[i]) {index[j]++;}}index[queries[i]] = 0;}return ans;}}
解法二:树状数组
参考:https://leetcode-cn.com/problems/queries-on-a-permutation-with-key/solution/cha-xun-dai-jian-de-pai-lie-by-leetcode-solution/
关于区间查询、单点更新的树状数组,参见:https://www.yuque.com/herormluzhan/uup252/noom0v
class Solution {private class TreeArray {// 树状数组,下标从1开始private int[] value;// 长度private final int length;public TreeArray(int n) {length = n;value = new int[length + 1];}public TreeArray(int[] arr) {length = arr.length;value = new int[length + 1];for (int i = 1; i <= length; ++i) {update(i, arr[i - 1]);}}/*** k:x的二进制形式从最低位到最高位连续0的个数* 求2^k** @param x 非负整数* @return 2^k*/private int lowBit(int x) {return x & (-x);}/*** 原数组的第i个元素增加k,更新树状数组的值** @param i 原数组元素索引位置* @param k 更新值*/public void update(int i, int k) {while (i <= length) {value[i] += k;i += lowBit(i);}}/*** 求[1,i]这i个数的和** @param i 索引位置* @return 前i个数的和*/public int getSum(int i) {int sum = 0;while (i >= 1) {sum += value[i];i -= lowBit(i);}return sum;}}public int[] processQueries(int[] queries, int m) {int[] ans = new int[queries.length];// 1 表示有数占据;0 表示没有数占据// 一开始将原来的 m 个数放到树状数组的最后 m 位TreeArray t = new TreeArray(queries.length + m);for (int i = 1; i <= m; ++i) {t.update(i + queries.length, 1);}// pos[i] 表示 i 在树状数组中的位置int[] pos = new int[m + 1];for (int i = 1; i <= m; ++i) {pos[i] = i + queries.length;}for (int i = 0; i < queries.length; ++i) {int curPos = pos[queries[i]];ans[i] = t.getSum(curPos - 1);// 从原来位置移动到队列首位// 将树状数组的原来位置从 1 置为 0,将新位置从 0 置为 1t.update(curPos, -1);pos[queries[i]] = queries.length - i;t.update(pos[queries[i]], 1);}return ans;}}
