算法题札记#1 - A programmer's perspective - SegmentFault
这篇文章只是记录一些关于我最近做算法题的思路,大部分比较好的思路都是参考网友的。由于只是提取了思路,因此没有标明是哪个网友的想法,见谅。
1. BinarySortTree -> Sorted Double Link List(简单)
二叉树节点的结构和双向列表节点结构是一样的。形如:
struct Node{ int m_nValue; struct Node * m_pLeft; struct Node * m_pRight; } 所以转换的时候,只要调整2个指针的指向就可以了。转换的思路,递归的方法,分3步走:
递归处理左子树
处理父节点。(逻辑基本上在这里实现)
递归处理友子树
转换后得到的是排好序的双向链表。
注意:这个转换是不可逆的,不同的BSTree可以转换成一样的双向链表。
2. 设计一个可以求最小值的Stack。要求栈的push,pop,以及min操作都是O(1)
Stack的push和pop操作可以做到O(1),但是min操作不能直管做到O(1),正常来说,需要O(n)。
如果min要做到O(1),则需要增加空间消耗,在push和pop的时候,保存nMin,这样min操作可以做到O(1),但是push和pop就不能直观做到O(1)了。
第一种做法,是每个push的操作,除了保存必要的value外,增加一个min值,如:
struct Node{ int m_nValue; int m_nMin; struct Node *m_pLast; } 这样每次push只要比较一下上一个节点的nMin就可以计算出最新的nMin。
第二种做法,不需要每个节点都保存nMin。只需要一个独立于常规Stack的变量来记录最小值就可以了。这种做法比较取巧,但是更接近于解决问题的本质。首先分析问题:
每个
push操作可能改变当前Stack的最小值。如果
push操作改变了Stack的最小值,则相应的pop操作需要还原最小值。
所以每个push操作,当改变最小值时,需要记录上一个最小值,这样在pop的时候就可以还原。
如果使用2个变量,是不能解决这个问题的,因为连续的push会冲刷掉旧的次最小值。只有用相应于常规Stack的另一个数组才能解决问题,如第一种解法。
但是第二种做法的精妙,在于push在储存结构中的值,不是直观上push的值,而是一个附带次最小值信息的值,用nValueInStorage来表示这个值。这个值能够在适当的时机算出push的值,以及nLastMin值。怎么做到呢,首先还原整个push步骤:
push nValuePushedcompare nValuePushed nMin
如果nValuePushed >= nMin,则nMin不变,nValueInStorage=nValuePushed。否则:
求包含
nValuePushed和nMin的nValueInStoragenMin = nValuePushed if <
最后:
Stack push nValueInStorage
现在的问题是,怎么求这个nValueInStorage。
因为
nValuePushed < nMin,所以-nValuePushed > -nMin-nValuePushed + 2 * nValuePushed > 2*nValuePushed - nMinnValuePushed > 2*nValuePushed - nMin(nValueInStorage = 2*nValuePushed - nMin) < nValuePushed
因为传统的做法,是不可能出现Stackpop的值小于nMin。所以这种做法正是利用这种特殊的情况,见缝插针:只要保证计算出来的nValueInStorage< nValuePushed。
当每次pop的时候,如果nValueInStorage>=nMin,则不需要更新,如果nValueInStorage<nMin,则更新。在更新的时候,需要从nValueInStorage提取nLastMin:
nMin = nLastMin = 2* nMin - nValueInStorage
Read full article from 算法题札记#1 - A programmer's perspective - SegmentFault
No comments:
Post a Comment