数据结构 《18》----RMQ 与 LCA 的等价性 (一)

前言

    RMQ: 数组 a0, a1, a2,..., an-1, 中求任意区间 a[i+1], a[i+2], ..., a[i+k] 的最小值


    LCA: 求二叉树中两个节点的最低公共祖先


    本文将证明这两个问题可以相互归约为另一个问题。


证明

   先通过一个简单的例子来说明问题。见下图:


   求 [7 2 8 6] 的最小值 2,等价于求二叉树中节点 7 和 节点6的 LCA,也就是 节点2。

   有意思吧。。。


一、 RMQ -> LCA

   给定一个数组,如何求出其对于的二叉树呢??

     方法1: 这棵二叉树其实具有类似最小堆的性质(虽然不是完全二叉树),

                  可以采用递归建树,先找到最小值作为 root 节点,然后对最小值左半边和右半边递归建左子树和右子树即可。

    复杂度: 最好 O(NlgN),最坏 O(N^2), 分析类似与快排。。

/**
 * recursive version
 * build a RMQ tree
 * */
Node* BuildTree(int *a, int left, int right)
{
  //EXIT
  if(left > right) return NULL;

  Node *root(NULL);
  int min_index = min_element(a+left, a+right+1) - a;
  root = new Node(a[min_index]);
  root->left = BuildTree(a, left, min_index - 1);
  root->right = BuildTree(a, min_index+1, right);

  return root;
}

     方法2:因此扫描数组的每一个元素,将元素按如下规则插入树中;

                 从根节点出发,一直往右孩子移动,直到当前插入元素值位于一个 父亲节点和右孩子节点之间。

                 将插入节点作为 父亲节点的右孩子,之前的右子树作为插入节点的左子树。

       

/**
 * O(n) version
 * build a RMQ tree
 */
Node* BuildTree2(int *a, int left, int right)
{
  Node *root(NULL), *cur(NULL), *pre(NULL);
  Node *node(NULL);
  for(int i=left; i<=right; ++i)
  {
    //like inserting into a sorted list
    pre = NULL; cur = root;
    while(cur && cur->val < a[i]){
      pre = cur;
      cur = cur->right;
    }
    node = new Node(a[i]);
    node->left = cur;
    if(pre == NULL){
      root = node;
    }
    else{
      pre->right = node;
    }
  }
  return root;
}

二、LCA -> RMQ

如何将一个 LCA 归约到一个数组求区间最小值呢?? 这个问题有一个 trick.

加入我们的二叉树如下图,注意,它并不满足最小堆的性质!!!

   1. 做一个变换,将节点的值改成节点的深度,这样,新的二叉树就满足了最小堆的性质;

       这两颗树的节点是一一对应的,

       求 LCA(node3, node8) 对应于 在新树中求 LCA(node3, node1)


    2. 新树中求 LCA(node3, node1) 对应于在新树的中序遍历序列 2 1 3 2 0 1 中求 【3 2 0 1】的最小值;






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值