1409. Queries on a Permutation With Key

问题:

给定一个数字m,则有一个数组Array:1~m分别在数组的0~m-1位上放置。

在给定一个操作对象数组 queries,表示操作对象数字,

返回当前该数字的位置到结果数组res中,并将该数字移到Array数组开头。

求操作完所有queries中的对象后,得到的res。

Example 1:
Input: queries = [3,1,2,1], m = 5
Output: [2,1,2,1] 
Explanation: The queries are processed as follow: 
For i=0: queries[i]=3, P=[1,2,3,4,5], position of 3 in P is 2, then we move 3 to the beginning of P resulting in P=[3,1,2,4,5]. 
For i=1: queries[i]=1, P=[3,1,2,4,5], position of 1 in P is 1, then we move 1 to the beginning of P resulting in P=[1,3,2,4,5]. 
For i=2: queries[i]=2, P=[1,3,2,4,5], position of 2 in P is 2, then we move 2 to the beginning of P resulting in P=[2,1,3,4,5]. 
For i=3: queries[i]=1, P=[2,1,3,4,5], position of 1 in P is 1, then we move 1 to the beginning of P resulting in P=[1,2,3,4,5]. 
Therefore, the array containing the result is [2,1,2,1].  

Example 2:
Input: queries = [4,1,2,2], m = 4
Output: [3,1,2,0]

Example 3:
Input: queries = [7,5,5,8,3], m = 8
Output: [6,5,0,7,5]
 
Constraints:
1 <= m <= 10^3
1 <= queries.length <= m
1 <= queries[i] <= m

  

解法:

Constraints:
1 <= m <= 10^3

则可说明,该问题满足 m*m 的时间复杂度
leetcode允许运行时间10^6

 

解法一:

position记录法,

完全按照题意,进行操作,

只是使用pos数组记录每个数字的位置。(hash方便查找)

pos[q]=j 代表数字 q 所在的位置在 j 上。

那么queries中的每一个数字 i 即能瞬间找到其对应位置pos[q]。

找到后,res.push_back(pos[q])

同时对1~m的所有数字的位置进行更新:

1.pos[i] < pos[q] :都往后移动一位:pos[i]++

2.pos[q]=0:把q移动到首位。

 

代码参考:

 1 class Solution {
 2 public:
 3     vector<int> processQueries(vector<int>& queries, int m) {
 4         vector<int> pos(m+1);
 5         vector<int> res;
 6         iota(pos.begin(), pos.end(), -1);//从pos[0]=-1开始,pos[i]=(pos[i-1]++);
 7         for(int q:queries){
 8             res.push_back(pos[q]);
 9             for(int i=1; i<=m; i++){
10                 if(pos[i]<pos[q]) pos[i]++;
11             }
12             pos[q]=0;
13         }
14         return res;
15     }
16 };

 

解法二:

Fenwick Tree方法:

Fenwick Tree介绍:https://zxi.mytechroad.com/blog/sp/fenwick-tree-binary-indexed-tree-sp3/

【转自:花花酱 的博客,地址如上】

一般对应问题:

求数组前缀和(query方法)。(且中间含有多次,单独更新(update方法)其中某个值的操作)

解法思想:存储连续多个元素之和->使得所求=多个既存连续组之和。(空间换时间)

选择元素和的根据:Tree->使得时间复杂度为: log n

选择方法:

  • partsum[1]=元素1的值=1                                                            【1】
  • partsum[2]=元素1+元素2的值=1+2=3                                           【1-2】
  • partsum[3]=元素3的值=3                                                          【3】
  • partsum[4]=partsum[2]+partsum[3]+元素4的值=1+2+3+4=6+4=10  【1-4】
  • ……

那么当我们要求前3个数之和的时候,

我们要用【3】+【1-2】= partsum[3]+partsum[2]=3+3=6

要得到上述的Tree,使用lowbit方法进行构建:

对要更新的数,取二进制,对该数+=该数的(为1的)最低位,都进行更新。如要更新1,则需更新1(1),2(10),4(100),8(1000)...直到最后一个数。

求和,则对该数取二进制,累加:对该数-=该数的(为1的)最低位。如要求7,则累加7(111)+6(110)+4(100)

 

 

 

 对于本问题:

由于FenwickTree能将变动一个元素,并查找前缀累计的问题,时间复杂度转为log n

那么,我们可以将本问题,转化为:

在给定数组前面再预留queries.size的空位,用来插入所要插入的数字,

插入后,将该数字原来的位置置空即可。其他数字位置不变。

因为要求指定数字的位置,要联系到前缀和,那么我们将存在数字的位置置为1,前缀和,即为该数字目前的位置。

另外,同样我们为了快速定位数字位置,引入pos[]的hash用来记录位置。

下图的

每一行,代表queries中的一次操作。

每一个cell

如第8位-> 3:1 其中3表示数字,并不实际存在tree中,后面的1才是我们要存在tree中的内容。

而pos[3]=8来确定3所在的位置。

 

 代码参考:

 1 class FenwickTree {
 2 private:
 3     vector<int> preSum;
 4     int size;
 5     int lowbit(int x) {
 6         return x&(-x);
 7     }
 8 public:
 9     FenwickTree(int n):preSum(n+1, 0), size(n+1) {};
10     void update(int idx, int delta) {
11         idx++;//update idx(0~idx)-> update preSum[idx+1]
12         while(idx<size) {
13             preSum[idx] += delta;
14             idx += lowbit(idx);
15         }
16     }
17     int getSum(int idx) {
18         int res = 0;
19         while(idx>0) {
20             res += preSum[idx];
21             idx -= lowbit(idx);
22         }
23         return res;
24     }
25 };
26 
27 class Solution {
28 public:
29     vector<int> processQueries(vector<int>& queries, int m) {
30         vector<int> res;
31         int n = queries.size();
32         vector<int> pos(m+1); // pos[1~m]=0~m-1;
33         FenwickTree ft(m+n);
34         for(int i=1; i<=m; i++) {
35             pos[i] = n+i-1;
36             ft.update(pos[i], 1);
37         }
38         for(auto q:queries) {
39             res.push_back(ft.getSum(pos[q]));
40             ft.update(pos[q], -1);
41             pos[q] = n-1;
42             ft.update(pos[q], 1);
43             n--;
44         }
45         return res;
46     }
47 };

 

posted @ 2020-07-31 16:21  habibah_chang  阅读(116)  评论(0编辑  收藏  举报