zoukankan      html  css  js  c++  java
  • 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> partSum;
     4     int lowest1bit(int num){
     5         return num & (-num);
     6         //-num = ~num+1
     7         //e.g. num=5 (0110) -> -num = -5 = ~(0110)+1 = 1001 +1 = 1010
     8         // num & (-num) = 0110 & 1010 = 0010
     9     }
    10 public:
    11     FenwickTree(int n):partSum(n+1,0) {}
    12     //update all the item in the partition Sum route of i
    13     void update(int i, int val){
    14         while(i<partSum.size()){
    15             partSum[i]+=val;
    16             i+=lowest1bit(i);
    17         }
    18     }
    19     //find Sum(0~i)
    20     int query(int i){
    21         int sum=0;
    22         while(i>0){
    23             sum+=partSum[i];
    24             i-=lowest1bit(i);
    25         }
    26         return sum;
    27     }
    28 };
    29 
    30 class Solution {
    31 public:
    32     vector<int> processQueries(vector<int>& queries, int m) {
    33         vector<int> pos(m+1);
    34         vector<int> res;
    35         int qsize=queries.size();
    36         FenwickTree tree(m+qsize+1);
    37         for(int i=1; i<=m; i++){
    38             pos[i]=qsize+i;
    39             tree.update(pos[i],1);
    40         }
    41         
    42         for(int q:queries){
    43             res.push_back(tree.query(pos[q]-1));
    44             tree.update(pos[q],-1);
    45             pos[q]=qsize;
    46             tree.update(qsize,1);
    47             qsize--;
    48         }
    49         return res;
    50     }
    51 };
  • 相关阅读:
    uva 12169 Disgruntled Judge
    uva 11582 Colossal Fibonacci Numbers!
    ACdream 1073
    ACdream 1061 郭式树
    《构建之法》读书笔记
    南阳oj 素数求和问题
    hdoj Problem-1007 A hard puzzle
    程序员不得不知的 Navicat 实用工具
    Beyond Compare怎么对比图片差异
    教您用Beyond Compare比较十六进制文件
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/13410402.html
Copyright © 2011-2022 走看看