算法题札记#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 nValuePushed
compare nValuePushed nMin
如果nValuePushed >= nMin
,则nMin
不变,nValueInStorage=nValuePushed
。否则:
求包含
nValuePushed
和nMin
的nValueInStorage
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
Read full article from 算法题札记#1 - A programmer's perspective - SegmentFault
No comments:
Post a Comment