算法题札记#1 - A programmer's perspective - SegmentFault



算法题札记#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步走:

  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


Read full article from 算法题札记#1 - A programmer's perspective - SegmentFault


No comments:

Post a Comment

Labels

Algorithm (219) Lucene (130) LeetCode (97) Database (36) Data Structure (33) text mining (28) Solr (27) java (27) Mathematical Algorithm (26) Difficult Algorithm (25) Logic Thinking (23) Puzzles (23) Bit Algorithms (22) Math (21) List (20) Dynamic Programming (19) Linux (19) Tree (18) Machine Learning (15) EPI (11) Queue (11) Smart Algorithm (11) Operating System (9) Java Basic (8) Recursive Algorithm (8) Stack (8) Eclipse (7) Scala (7) Tika (7) J2EE (6) Monitoring (6) Trie (6) Concurrency (5) Geometry Algorithm (5) Greedy Algorithm (5) Mahout (5) MySQL (5) xpost (5) C (4) Interview (4) Vi (4) regular expression (4) to-do (4) C++ (3) Chrome (3) Divide and Conquer (3) Graph Algorithm (3) Permutation (3) Powershell (3) Random (3) Segment Tree (3) UIMA (3) Union-Find (3) Video (3) Virtualization (3) Windows (3) XML (3) Advanced Data Structure (2) Android (2) Bash (2) Classic Algorithm (2) Debugging (2) Design Pattern (2) Google (2) Hadoop (2) Java Collections (2) Markov Chains (2) Probabilities (2) Shell (2) Site (2) Web Development (2) Workplace (2) angularjs (2) .Net (1) Amazon Interview (1) Android Studio (1) Array (1) Boilerpipe (1) Book Notes (1) ChromeOS (1) Chromebook (1) Codility (1) Desgin (1) Design (1) Divide and Conqure (1) GAE (1) Google Interview (1) Great Stuff (1) Hash (1) High Tech Companies (1) Improving (1) LifeTips (1) Maven (1) Network (1) Performance (1) Programming (1) Resources (1) Sampling (1) Sed (1) Smart Thinking (1) Sort (1) Spark (1) Stanford NLP (1) System Design (1) Trove (1) VIP (1) tools (1)

Popular Posts