演算法連結串列筆試題(一)
1、移除重複節點
https://leetcode-cn.com/problems/remove-duplicate-node-lcci/
編寫程式碼,移除未排序連結串列中的重複節點。保留最開始出現的節點。
示例1:
輸入:[1, 2, 3, 3, 2, 1]
輸出:[1, 2, 3]
示例2:
輸入:[1, 1, 1, 1, 2]
輸出:[1, 2]
提示:
連結串列長度在[0, 20000]範圍內。
連結串列元素在[0, 20000]範圍內。
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * }*/ class Solution { public ListNode removeDuplicateNodes(ListNode head) { if(head == null){ return null; } Set<Integer> set = new HashSet<>(); ListNode cur = head; set.add(cur.val); while (cur.next != null){ if(set.add(cur.next.val)){ cur= cur.next; }else{ cur.next = cur.next.next; } } return head; } }
解析:
雜湊表法:對給定的連結串列進行一次遍歷,並用一個雜湊集合(HashSet)來儲存所有出現過的節點。在雜湊集合中儲存連結串列元素的值,方便直接使用等號進行比較。
2、迴文連結串列
https://leetcode-cn.com/problems/palindrome-linked-list-lcci/
編寫一個函式,檢查輸入的連結串列是否是迴文的。
示例 1:
輸入: 1->2
輸出: false
示例 2:
輸入: 1->2->2->1
輸出: true
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public boolean isPalindrome(ListNode head) { List<Integer> list = new ArrayList<>(); ListNode cur = head; while(cur != null){ list.add(cur.val); cur = cur.next; } int front = 0; int backend = list.size()-1; while(front<backend){ if(!list.get(front).equals(list.get(backend))){ return false; } front++; backend--; } return true; } }
解析:
一共為兩個步驟:
1、複製連結串列值到陣列列表中。
2、使用雙指標法判斷是否為迴文。
第一步,我們需要遍歷連結串列將值複製到陣列列表中。我們用 currentNode 指向當前節點。每次迭代向陣列新增 currentNode.val,並更新 currentNode = currentNode.next,當 currentNode = null 時停止迴圈。
最好使用雙指標法來檢查是否為迴文。我們在起點放置一個指標,在結尾放置一個指標,每一次迭代判斷兩個指標指向的元素是否相同,若不同,返回 false;相同則將兩個指標向內移動,並繼續判斷,直到兩個指標相遇。
3、連結串列相交
https://leetcode-cn.com/problems/intersection-of-two-linked-lists-lcci/
給你兩個單鏈表的頭節點headA 和 headB ,請你找出並返回兩個單鏈表相交的起始節點。如果兩個連結串列沒有交點,返回 null 。
圖示兩個連結串列在節點 c1 開始相交:
題目資料 保證 整個鏈式結構中不存在環。
注意,函式返回結果後,連結串列必須 保持其原始結構 。
示例 1:
輸入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
輸出:Intersected at '8'
解釋:相交節點的值為 8 (注意,如果兩個連結串列相交則不能為 0)。
從各自的表頭開始算起,連結串列 A 為 [4,1,8,4,5],連結串列 B 為 [5,0,1,8,4,5]。
在 A 中,相交節點前有 2 個節點;在 B 中,相交節點前有 3 個節點。
示例2:
輸入:intersectVal= 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
輸出:Intersected at '2'
解釋:相交節點的值為 2 (注意,如果兩個連結串列相交則不能為 0)。
從各自的表頭開始算起,連結串列 A 為 [0,9,1,2,4],連結串列 B 為 [3,2,4]。
在 A 中,相交節點前有 3 個節點;在 B 中,相交節點前有 1 個節點。
示例3:
輸入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
輸出:null
解釋:從各自的表頭開始算起,連結串列 A 為 [2,6,4],連結串列 B 為 [1,5]。
由於這兩個連結串列不相交,所以 intersectVal 必須為 0,而 skipA 和 skipB 可以是任意值。
這兩個連結串列不相交,因此返回 null 。
提示:
listA 中節點數目為 m
listB 中節點數目為 n
0 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
如果 listA 和 listB 沒有交點,intersectVal 為 0
如果 listA 和 listB 有交點,intersectVal == listA[skipA + 1] == listB[skipB + 1]
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { int aLength = 0; int bLength = 0; ListNode tmpA = headA; ListNode tmpB = headB; while(tmpA != null){ tmpA = tmpA.next; aLength++; } while(tmpB != null){ tmpB = tmpB.next; bLength++; } int grep = Math.abs(aLength - bLength);
// 這裡可以交換兩個連結串列,讓tmpA始終是較長的那個; tmpA = aLength > bLength ? headA : headB; tmpB = aLength > bLength ? headB : headA; while(grep > 0){ tmpA = tmpA.next; grep--; } while(tmpA != null){ if(tmpA == tmpB){ return tmpA; } tmpA = tmpA.next; tmpB = tmpB.next; } return null; } }
解析:
這個題要找到相同的節點,其實就是理解相同的含義。
如果兩個節點相同,那麼這兩個節點之後的節點也肯定都相同;
那麼意味著如果有相同的節點,從相同的節點往後長度一定相同。
所以只需要讓兩個連結串列長度對齊,讓長的連結串列先走一個長度差,再一起往後遍歷,遇到相同的就結束。
4、環路檢測
https://leetcode-cn.com/problems/linked-list-cycle-lcci/
給定一個連結串列,如果它是有環連結串列,實現一個演算法返回環路的開頭節點。若環不存在,請返回 null。
如果連結串列中有某個節點,可以通過連續跟蹤 next 指標再次到達,則連結串列中存在環。 為了表示給定連結串列中的環,我們使用整數 pos 來表示連結串列尾連線到連結串列中的位置(索引從 0 開始)。 如果 pos 是 -1,則在該連結串列中沒有環。注意:pos 不作為引數進行傳遞,僅僅是為了標識連結串列的實際情況。
示例 1:
輸入:head = [3,2,0,-4], pos = 1
輸出:tail connects to node index 1
解釋:連結串列中有一個環,其尾部連線到第二個節點。
示例 2:
輸入:head = [1,2], pos = 0
輸出:tail connects to node index 0
解釋:連結串列中有一個環,其尾部連線到第一個節點。
示例 3:
輸入:head = [1], pos = -1
輸出:no cycle
解釋:連結串列中沒有環。
/** * Definition for singly-linked list. * class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public ListNode detectCycle(ListNode head) { ListNode pos = head; Set<ListNode> set = new HashSet<>(); while(pos != null){ if(set.contains(pos)){ return pos; }else{ set.add(pos); } pos = pos.next; } return null; } }
解析:
遍歷連結串列中的每個節點,並將它記錄下來;一旦遇到了此前遍歷過的節點,就可以判定連結串列中存在環。藉助雜湊表可以很方便地實現