簡單LinkedList 的java代碼實現:
public class LinkedListNode {public int value;public LinkedListNode next;public LinkedListNode(int value) {this.value = value;this.next = null;}}
public class LinkedList {public LinkedListNode head;/*add an element to the tail*/public void add(int v) {if (head == null) {this.head = new LinkedListNode(v);} else {LinkedListNode node = head;while (node.next != null) {node = node.next;}node.next = new LinkedListNode(v);}}/*remove the element that appear first*/public void removeFirst(int v) {/* if to be removed is head node */if (head.value == v) {head = head.next;return;}/* iterate to the end and remove target node */LinkedListNode node = head;while (node.next != null) {if (node.next.value == v) {node.next = node.next.next;return;}node = node.next;}}public void print() {LinkedListNode node = head;while (node != null) {System.out.print(node.value + " ");node = node.next;}System.out.println();}}
1. Write code to remove duplicated element from an unsorted linked list. 從無序鏈表中重複資料刪除元素
來源 Cracking the Code Interview (2nd Edition) Ch2 Q1.
【解答】:題目已經明確說明是無序列表,對這類面試題,一般最差的複雜度是 O(NlogN),也就是需要一次排序過程,所以給出的答案最好要優於O(NlogN)。
方法一:除去重複元素,首先想到利用hash。將List迭代一遍,每拿出一個元素,放到hashtable裡,並判斷是否重複,如果重複則從List中刪除該元素。這個演算法的時間複雜度是O(N),但需要O(N)的空間建立hashtable去存放元素。
java代碼:http://pastebin.com/UiqMVxdL 這裡的linkedlist使用的是java.util.*中的LinkedList。實際面試中往往需要自己實現一個linkedlist。
public static void removeDuplicate(List<Integer> l){2. Hashtable table = new Hashtable();3. for(Iterator<Integer> iter = l.iterator();iter.hasNext();){4. Integer i = iter.next();5. if(table.containsKey(i)){6. iter.remove();7. }else{8. table.put(i, true);9. }10. }11. }
方法二:利用runner pointer. 這個技巧也是解答LinkedList Problem的重要技巧之一。迭代當前鏈表,每次迭代利用一個runner去訪問之後的元素,重複資料刪除元素。算是naive approach,時間複雜度O(N^2),空間複雜度O(1)。面試中最先可能想到的應該是這種解答,然後可以最佳化到第一種方法。
2. Implement am algorithm to find the kth to last element of a singly linked list. 尋找單項鏈表中,距最後一個元素距離為K的元素。
來源 Cracking the Code Interview (2nd Edition) Ch2 Q2.
【解答】:方法一:如果知道鏈表的長度N,答案就是從第(N-K)個元素。當然這題也就沒有意義了。
方法二:利用chaser-runner。首先讓runner先移動K位,這時候chaser從鏈表頭部開始,和runner同時以相同的速度迭代鏈表,當runner到達鏈表尾部,chaser恰好距離最後一個元素K的距離。時間複雜度O(N), 空間複雜度O(1)。
java代碼:http://pastebin.com/MQczDMvT 這裡用到的LinkedList是本文開始時定義的data structure.
public static LinkedListNode kth2Last(LinkedList list, int k) {2. LinkedListNode chaser = list.head;3. LinkedListNode runner = list.head;4. 5. int i = 0;6. 7. while (i < k) {8. /*the list must have at least k+1 elements*/9. if (runner == null) {10. return null;11. }12. runner = runner.next;13. i++;14. }15. 16. /*if the list has exactly k elements*/17. if(runner == null){18. return null;19. }20. 21. 22. /*begin chasing*/23. while(runner.next!=null){24. chaser = chaser.next;25. runner = runner.next;26. }27. return chaser;28. }
3. Given a circular linked list, implement an algorithm which returns the node at the beginning of the loop. 尋找有環鏈表環的頭部。
來源 Cracking the Code Interview (2nd Edition) Ch2 Q6.
【解答】: 這個題算是經典面試題之一,和Binary Tree的BFS遍曆一樣,都屬於看上去滿有水平,實際並沒有太多難度的題目,如果遇到了不會做人品可是敗成啥樣了!?
首先第一問一般是判斷該鏈表有沒有環,接著問如果有環的話,找出環開始的節點。
如果判斷是否有環?--Same technique as the last question. We can use
runner pointer to detect if there is a loop. 記得以前在學校裡跑1500米的時候,我經常被人套圈…類似的,如果一個鏈表有環,並且進入環以後,將一直在環裡走下去,慢的總是會被快的趕上,套圈。所以我們用兩個指標,一個slow runner,一個fast runner,每次slow走1個,fast走2個,如果在某個時刻slow == fast指標,則證明有環。
如何判斷環的開始是哪個節點?-- 這個問題也很容易想通。當兩個指標第一次相遇的時候,他們距離環的開始節點還有K個元素,而這K個元素是進入環之前那段鏈表元素的個數。怎麼證明呢?設想兩個runner同時從某個環的同一個點出發,快的runner以2倍於慢的runner速度前進,它們第一次重合一定還是在這個出發點的位置,以後每一次相遇也一定是在這個出發點的位置。So,設想現在進入環前的那一段K個節點,是環的一部分,離環真正的開始節點距離為K,那麼兩個runner同時出發,第一次碰撞必然還是在距離環開始節點K的位置。所以,第一次碰撞時,隨便將任意一個runner回到鏈表頭部,此時兩個runner以同一速度前進,當他們再次相遇的節點,就是環的開始節點。
java代碼:http://pastebin.com/p35Cwgzv
public static LinkedListNode findBegin(LinkedList list){2. LinkedListNode slow = list.head;3. LinkedListNode fast = list.head;4. 5. /*find the first meeting point*/6. while(fast!=null){7. fast = fast.next.next;8. slow = slow.next;9. if(fast == slow){10. break;11. }12. }13. 14. /*check if there do have a loop*/15. if(fast == null){16. return null;17. }18. 19. slow = list.head;20. 21. /*find the beginning of the loop*/22. while(slow!=fast){23. slow = slow.next;24. fast = fast.next;25. }26. return fast;27. }
4. Implement a function to check if a linked list is a palindrome. 判斷鏈表是不是迴文鏈表。
來源 Cracking the Code Interview (2nd Edition) Ch2 Q7.
【解答】:經典面試題了。迴文就是 0-->1-->2-->1-->0 奇數個節點, 或者 0-->1-->2-->2-->1-->0 偶數個節點。
方法一:很自然的想法就是把鏈表反轉,然後對比反轉以後的鏈表和原鏈表的節點值,並且只要比較反轉鏈表和原鏈表一辦的元素就可以。
方法二:利用runner pointer。很多的題目都可以利用這個方法來解決。Runner pointer和遞迴是解決鏈表問題最常用的兩個方法。
定義兩個指標,slow runner和fast runner,fast以2倍於slow的速度向鏈表尾部移動。如有奇數個節點:當fast到達鏈表尾部時,slow恰好到達鏈表中間。如有偶數個節點:fast第一次為null時,slow恰好完成了一半節點的訪問。把slow訪問過的節點元素值壓入一個stack裡。此後slow繼續向鏈表尾部訪問,同時stack裡的元素開始出棧(奇數個元素的情況下要跳過中間元素),比較兩個元素值,一旦出現不等,則不是迴文,否則是。該解法的時間複雜度是O(N),因為需要一次迭代,同時需要O(N)的空間用作stack來存放鏈表元素。
java代碼 http://pastebin.com/wZ54iSmq 這裡的List是本文開始定義的資料結構。
1. public static boolean isPalindrome(LinkedList list){2. LinkedListNode slow = list.head;3. LinkedListNode fast = list.head;4. 5. Stack<Integer> stack = new Stack<Integer>();6. while(fast!=null&&fast.next!=null){7. stack.push(slow.value);8. slow = slow.next;9. fast = fast.next.next;10. }11. 12. /*if the length of list is odd*/13. if(fast!=null){14. slow = slow.next;15. }16. 17. /*compare elements all the way to the end*/18. while(slow!=null){19. if(slow.value!=stack.pop().intValue()){20. return false;21. }22. slow = slow.next;23. }24. return true;25. }
轉載:http://blog.csdn.net/tanglinghui/article/details/7618142