解法一:模拟

记录每个数的下标位置,每次查询直接给出结果,然后更新下标数组:比该位置小的都加1,该位置的值更新为0。
时间复杂度:1409. 查询带键的排列 - 图1

  1. class Solution {
  2. public int[] processQueries(int[] queries, int m) {
  3. int[] index = new int[m + 1];
  4. for (int i = 1; i <= m; ++i) {
  5. index[i] = i - 1;
  6. }
  7. int[] ans = new int[queries.length];
  8. for (int i = 0; i < queries.length; ++i) {
  9. ans[i] = index[queries[i]];
  10. for (int j = 1; j <= m; ++j) {
  11. if (index[j] < ans[i]) {
  12. index[j]++;
  13. }
  14. }
  15. index[queries[i]] = 0;
  16. }
  17. return ans;
  18. }
  19. }

解法二:树状数组

参考: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

  1. class Solution {
  2. private class TreeArray {
  3. // 树状数组,下标从1开始
  4. private int[] value;
  5. // 长度
  6. private final int length;
  7. public TreeArray(int n) {
  8. length = n;
  9. value = new int[length + 1];
  10. }
  11. public TreeArray(int[] arr) {
  12. length = arr.length;
  13. value = new int[length + 1];
  14. for (int i = 1; i <= length; ++i) {
  15. update(i, arr[i - 1]);
  16. }
  17. }
  18. /**
  19. * k:x的二进制形式从最低位到最高位连续0的个数
  20. * 求2^k
  21. *
  22. * @param x 非负整数
  23. * @return 2^k
  24. */
  25. private int lowBit(int x) {
  26. return x & (-x);
  27. }
  28. /**
  29. * 原数组的第i个元素增加k,更新树状数组的值
  30. *
  31. * @param i 原数组元素索引位置
  32. * @param k 更新值
  33. */
  34. public void update(int i, int k) {
  35. while (i <= length) {
  36. value[i] += k;
  37. i += lowBit(i);
  38. }
  39. }
  40. /**
  41. * 求[1,i]这i个数的和
  42. *
  43. * @param i 索引位置
  44. * @return 前i个数的和
  45. */
  46. public int getSum(int i) {
  47. int sum = 0;
  48. while (i >= 1) {
  49. sum += value[i];
  50. i -= lowBit(i);
  51. }
  52. return sum;
  53. }
  54. }
  55. public int[] processQueries(int[] queries, int m) {
  56. int[] ans = new int[queries.length];
  57. // 1 表示有数占据;0 表示没有数占据
  58. // 一开始将原来的 m 个数放到树状数组的最后 m 位
  59. TreeArray t = new TreeArray(queries.length + m);
  60. for (int i = 1; i <= m; ++i) {
  61. t.update(i + queries.length, 1);
  62. }
  63. // pos[i] 表示 i 在树状数组中的位置
  64. int[] pos = new int[m + 1];
  65. for (int i = 1; i <= m; ++i) {
  66. pos[i] = i + queries.length;
  67. }
  68. for (int i = 0; i < queries.length; ++i) {
  69. int curPos = pos[queries[i]];
  70. ans[i] = t.getSum(curPos - 1);
  71. // 从原来位置移动到队列首位
  72. // 将树状数组的原来位置从 1 置为 0,将新位置从 0 置为 1
  73. t.update(curPos, -1);
  74. pos[queries[i]] = queries.length - i;
  75. t.update(pos[queries[i]], 1);
  76. }
  77. return ans;
  78. }
  79. }