这篇文章只是记录一些关于我最近做算法题的思路,大部分比较好的思路都是参考网友的。由于只是提取了思路,因此没有标明是哪个网友的想法,见谅。

1. BinarySortTree -> Sorted Double Link List(简单)

二叉树节点的结构和双向列表节点结构是一样的。形如:

struct Node{
    int m_nValue;
    struct Node * m_pLeft;
    struct Node * m_pRight;
}

所以转换的时候,只要调整2个指针的指向就可以了。转换的思路,递归的方法,分3步走:

  1. 递归处理左子树

  2. 处理父节点。(逻辑基本上在这里实现)

  3. 递归处理友子树

转换后得到的是排好序的双向链表。
注意:这个转换是不可逆的,不同的BSTree可以转换成一样的双向链表。

2. 设计一个可以求最小值的Stack。要求栈的pushpop,以及min操作都是O(1)

Stack的pushpop操作可以做到O(1),但是min操作不能直管做到O(1),正常来说,需要O(n)。
如果min要做到O(1),则需要增加空间消耗,在pushpop的时候,保存nMin,这样min操作可以做到O(1),但是pushpop就不能直观做到O(1)了。

第一种做法,是每个push的操作,除了保存必要的value外,增加一个min值,如:

struct Node{
    int m_nValue;
    int m_nMin;
    struct Node *m_pLast;
}

这样每次push只要比较一下上一个节点的nMin就可以计算出最新的nMin

第二种做法,不需要每个节点都保存nMin。只需要一个独立于常规Stack的变量来记录最小值就可以了。这种做法比较取巧,但是更接近于解决问题的本质。首先分析问题:

  1. 每个push操作可能改变当前Stack的最小值。

  2. 如果push操作改变了Stack的最小值,则相应的pop操作需要还原最小值。

所以每个push操作,当改变最小值时,需要记录上一个最小值,这样在pop的时候就可以还原。
如果使用2个变量,是不能解决这个问题的,因为连续的push会冲刷掉旧的次最小值。只有用相应于常规Stack的另一个数组才能解决问题,如第一种解法。

但是第二种做法的精妙,在于push在储存结构中的值,不是直观上push的值,而是一个附带次最小值信息的值,用nValueInStorage来表示这个值。这个值能够在适当的时机算出push的值,以及nLastMin值。怎么做到呢,首先还原整个push步骤:

  • push nValuePushed

  • compare nValuePushed nMin

如果nValuePushed >= nMin,则nMin不变,nValueInStorage=nValuePushed。否则:

  • 求包含nValuePushednMinnValueInStorage

  • nMin = nValuePushed if <

最后:

  • Stack push nValueInStorage

现在的问题是,怎么求这个nValueInStorage

  • 因为nValuePushed < nMin,所以-nValuePushed > -nMin

  • -nValuePushed + 2 * nValuePushed > 2*nValuePushed - nMin

  • nValuePushed > 2*nValuePushed - nMin

  • (nValueInStorage = 2*nValuePushed - nMin) < nValuePushed

因为传统的做法,是不可能出现Stackpop的值小于nMin。所以这种做法正是利用这种特殊的情况,见缝插针:只要保证计算出来的nValueInStorage< nValuePushed

当每次pop的时候,如果nValueInStorage>=nMin,则不需要更新,如果nValueInStorage<nMin,则更新。在更新的时候,需要从nValueInStorage提取nLastMin:

  • nMin = nLastMin = 2* nMin - nValueInStorage


jaryguo
148 声望2 粉丝

A game programmer, enjoy working on OSX with terminal.