找到框的顺序

时间:2016-06-05 11:57:46

标签: algorithm

架子上有盒子,每个盒子都有一个与之关联的ID号。有Q查询。

每个查询都采用l r形式,并通过将包含范围内的所有框移动到工具架的头部(正面)来执行查询。

鉴于查询和所有方框的初始排序,您能在货架上找到方框ID的最终订购吗?

示例输入:

6
1 2 3 4 5 6
3
4 5
3 4
2 3

示例输出:

2 4 1 5 3 6

说明:

架子最初看起来像这样:[1,2,3,4,5,6]。我们按以下顺序执行查询:

  1. 将4 th 和5 th 项目移到前面,所以我们的架子如下所示:[4,5,1,2,3,6]
  2. 将3 rd 和4 th 项目移到前面,所以我们的书架如下所示:[1,2,4,5,3,6]
  3. 将2 nd 和3 rd 项目移到前面,所以我们的架子如下所示:[2,4,1,5,3,6]
  4. 然后我们打印这个ID号的最终排序作为我们的答案。

    Question Link

    有没有比O(Q*N)更好的解决方案?

3 个答案:

答案 0 :(得分:3)

(另见Kundor对Onaka如何使用类似treap结构(How does a treap help to update this ordered queue?)的出色解释。)

rope结构可以允许O(m log n)时间解决方案。除了根之外,二叉树中的每个节点都存储其左子树的权重;在我们的例子中,权重是元素的数量。我们列表的当前顺序从左到右存储在叶子中。

可以通过跟随节点在ith to jth时间内访问包含当前O(log n)元素的子树:如果i小于节点权重,则向左;否则,从i减去左侧节点的权重,然后向右移动。

要移动元素,请拆分包含它们的子树(更新侧边),并将拆分部分与树的前部连接起来。您可能需要考虑如何使树保持合理平衡。

以下示例将元素的索引存储在原始列表中(非零),而不是元素本身,以允许范围条目(例如,1-3):

input [1,2,3,4,5,6]

rope     6
       (1-6)


1. Move 4th-5th to front:

         2    |    3    |   1
split  (4-5)  |  (1-3)  |  (6)

concat          6
                5
         2              1
   (4-5)   (1-3)       (6)


2. Move 3rd-4th to front:

split           4           |
                3           |
         2              1   |     2
   (4-5)    (3)   (6)       |   (1-2)

concat         6
       2                 3
     (1-2)         2           1
             (4-5)   (3)      (6)

3. Move 2nd-3rd to front:

split        4                 |
       2             2         |
      (1)       1         1    |     2
             (5) (3)     (6)   |   (2,4)

concat        6
              3
       2               2
   2       1       1        1
 (2,4)    (1)   (5) (3)    (6)

答案 1 :(得分:0)

正如Gassa指出的那样,你可以使用一个splay树。

在(未经测试!)C中,结构看起来像

// Splay tree of boxes
struct Box {
    struct Box *left;  // root of the left subtree
    struct Box *right;  // root of the right subtree
    struct Box *parent;
    int left_size;  // size of the left subtree
    int id;  // box id
};

一些基本的操作例程:

void box_init(struct Box *box, int id) {
    box->left = box->right = box->parent = NULL;
    box->left_size = 0;
    box->id = id;
}

void box_link_left(struct Box *box1, struct Box *box2, int box2_size) {
    box1->left = box2;
    box1->left_size = box2_size;
    if (box2 != NULL) {
        box2->parent = box1;
    }
}

void box_link_right(struct Box *box1, struct Box *box2) {
    box1->right = box2;
    if (box2 != NULL) {
        box2->parent = box1;
    }
}

// Changes
//
//     box         left
//    /   \        / \
//  left   c  =>  a  box
//  / \              / \
// a   b            b   c
void box_rotate_right(struct Box *box) {
    struct Box *left = box->left;
    struct Box *parent = box->parent;
    if (parent == NULL) {
    } else if (parent->left == box) {
        parent->left = left;
    } else {
        parent->right = left;
    }
    box_link_left(box, left->right, box->left_size - left->left_size - 1);
    box_link_right(left, box);
}

void box_rotate_left(struct Box *box) {
    // code here
}

void box_splay_to_root(struct Box *box) {
    // code to bottom-up splay here
}

struct Box *box_rightmost(struct Box *box) {
    while (box->right != NULL) {
        box = box->right;
    }
    return box;
}

不寻常的部分是按索引找到一个方框:

struct Box *box_at(struct Box *root, int i) {
    struct Box *box = root;
    while (1) {
        if (i <= box->left_size) {
            box = box->left;
            continue;
        }
        i -= box->left_size;
        if (i == 1) {
            return box;
        }
        i--;
        box = box->right;
    }
}

并对盒子顺序进行手术:

struct Box *box_move_to_front(struct Box *root, int l, int r) {
    if (l == 1) {  // no-op
        return root;  // new root
    }
    struct Box *br = box_at(root, r);
    box_splay_to_root(br);
    // cut right of br
    struct Box *right_of_r = br->right;
    br->right = NULL;
    struct Box *bl1 = box_at(br, l - 1);
    // cut right of bl1
    struct Box *mid = bl1->right;
    // link
    bl1->right = right_of_r;
    // link
    mid = box_rightmost(mid);
    box_splay_to_root(mid);
    box_link_right(mid, bl1);
    return mid;  // new root
}

答案 2 :(得分:0)

对此有一个相当简单的实际解决方案。

它基于在保持索引数组的同时将数字附加到原​​始数据,[拾取次数]次。然后使用该索引数组从数据中获取结果。

这个想法是在数组的右侧工作,因为大多数系统支持有效的追加。或者,可以从开始将[2 *选择数]零添加到数据中,然后再填充。

这需要镜像原始数据。

伪:

data = 6 5 4 3 2 1  // Mirrored original data, an integer array, will increase in size

ind = 6 5 4 3 2 1   // A fixed size, length-6 (tot nr of picks) integer array

picks = (5 4)       // Row 1 - mirrored 2-column (and 3 row in this example) table
        (4 3)       // Row 2
        (3 2)       // Row 3

s = 6               // 6 is the total number of picks, ie. 2 * 3 (cols * rows)

:For row :In 1 2 3  // Loop through the pick rows
    a = 1 + s - picks[row;] // a is now a 2-element array, as picks[row] is 2 elements
    data ,= data[a] // Adding 2 elements to data per each cycle
    s += 2
    ind[data[a]] = (s - 1), s // 2 elements of ind get assigned (overwritten) here
:End

// Grab the result
// data is now: 6 5 4 3 2 1 5 4 2 1 4 2
// ind is now: 10 12 4 11 7 1
order = [grab the ascending sort order of ind] // Will be 6 3 5 1 4 2 in this example
result = data[ind[order]]     // Will be 6 3 5 1 4 2
result = [reverse of] result  // Will be 2 4 1 5 3 6

有一种替代方法可以获取结果,其中不需要索引维护(即.ind变量)或排序:

// Grab the result 2:
result = [unique] [mirror of] data
Imho,没有魔法可以得到结果。这个解决方案与选择数量的比例非常相称。