生活随笔
收集整理的這篇文章主要介紹了
算法入门篇五 链表
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
牛客網(wǎng) 算法入門篇
判斷一個鏈表是否為回文結(jié)構(gòu)
- 給定一個單鏈表的頭節(jié)點(diǎn)head,請判斷這個鏈表是否為回文結(jié)構(gòu)
- 1->2->1,返回為True;1->2->3為False
思路:
- 1,遍歷鏈表,將所有元素壓入棧中,然后再次從頭遍歷,和棧中取出的元素比較。如果所有元素都是一致的化,說明是屬于回文結(jié)構(gòu)的。
- 2,不是將所有的元素都入棧,只是將一般的元素壓入棧中,引出新的問題,如何確認(rèn)鏈表的中點(diǎn)?設(shè)計快指針和慢指針,快指針每次移動2步,慢指針每次移動1步,當(dāng)快指針移動到末尾,慢指針?biāo)赶虻奈恢镁褪擎湵淼闹悬c(diǎn)位置。但是,鏈表長度需要分奇數(shù)和偶數(shù)。(節(jié)約空間)
- 3,不需要使用棧,僅僅使用有限幾個變量。和方法2一致,使用快慢指針找到鏈表的中點(diǎn),將鏈表中點(diǎn)之后的元素逆序,然后逐一比較,但是需要注意的是,最后需要將鏈表變回原先的樣子。
代碼:
package class04;import java.util.Stack;public class Code04_IsPalindromeList {public static class Node {public int value;public Node next;public Node(int data) {this.value = data;}}// need n extra spacepublic static boolean isPalindrome1(Node head) {Stack<Node> stack = new Stack<Node>();Node cur = head;while (cur != null) {stack.push(cur);cur = cur.next;}while (head != null) {if (head.value != stack.pop().value) {return false;}head = head.next;}return true;}// need n/2 extra spacepublic static boolean isPalindrome2(Node head) {if (head == null || head.next == null) {return true;}Node right = head.next;Node cur = head;while (cur.next != null && cur.next.next != null) {right = right.next;cur = cur.next.next;}Stack<Node> stack = new Stack<Node>();while (right != null) {stack.push(right);right = right.next;}while (!stack.isEmpty()) {if (head.value != stack.pop().value) {return false;}head = head.next;}return true;}// need O(1) extra spacepublic static boolean isPalindrome3(Node head) {if (head == null || head.next == null) {return true;}Node n1 = head;Node n2 = head;while (n2.next != null && n2.next.next != null) { // find mid noden1 = n1.next; // n1 -> midn2 = n2.next.next; // n2 -> end}n2 = n1.next; // n2 -> right part first noden1.next = null; // mid.next -> nullNode n3 = null;while (n2 != null) { // right part convertn3 = n2.next; // n3 -> save next noden2.next = n1; // next of right node convertn1 = n2; // n1 moven2 = n3; // n2 move}n3 = n1; // n3 -> save last noden2 = head;// n2 -> left first nodeboolean res = true;while (n1 != null && n2 != null) { // check palindromeif (n1.value != n2.value) {res = false;break;}n1 = n1.next; // left to midn2 = n2.next; // right to mid}n1 = n3.next;n3.next = null;while (n1 != null) { // recover listn2 = n1.next;n1.next = n3;n3 = n1;n1 = n2;}return res;}public static void printLinkedList(Node node) {System.out.print("Linked List: ");while (node != null) {System.out.print(node.value + " ");node = node.next;}System.out.println();}public static void main(String[] args) {Node head = null;printLinkedList(head);System.out.print(isPalindrome1(head) + " | ");System.out.print(isPalindrome2(head) + " | ");System.out.println(isPalindrome3(head) + " | ");printLinkedList(head);System.out.println("=========================");head = new Node(1);printLinkedList(head);System.out.print(isPalindrome1(head) + " | ");System.out.print(isPalindrome2(head) + " | ");System.out.println(isPalindrome3(head) + " | ");printLinkedList(head);System.out.println("=========================");head = new Node(1);head.next = new Node(2);printLinkedList(head);System.out.print(isPalindrome1(head) + " | ");System.out.print(isPalindrome2(head) + " | ");System.out.println(isPalindrome3(head) + " | ");printLinkedList(head);System.out.println("=========================");head = new Node(1);head.next = new Node(1);printLinkedList(head);System.out.print(isPalindrome1(head) + " | ");System.out.print(isPalindrome2(head) + " | ");System.out.println(isPalindrome3(head) + " | ");printLinkedList(head);System.out.println("=========================");head = new Node(1);head.next = new Node(2);head.next.next = new Node(3);printLinkedList(head);System.out.print(isPalindrome1(head) + " | ");System.out.print(isPalindrome2(head) + " | ");System.out.println(isPalindrome3(head) + " | ");printLinkedList(head);System.out.println("=========================");head = new Node(1);head.next = new Node(2);head.next.next = new Node(1);printLinkedList(head);System.out.print(isPalindrome1(head) + " | ");System.out.print(isPalindrome2(head) + " | ");System.out.println(isPalindrome3(head) + " | ");printLinkedList(head);System.out.println("=========================");head = new Node(1);head.next = new Node(2);head.next.next = new Node(3);head.next.next.next = new Node(1);printLinkedList(head);System.out.print(isPalindrome1(head) + " | ");System.out.print(isPalindrome2(head) + " | ");System.out.println(isPalindrome3(head) + " | ");printLinkedList(head);System.out.println("=========================");head = new Node(1);head.next = new Node(2);head.next.next = new Node(2);head.next.next.next = new Node(1);printLinkedList(head);System.out.print(isPalindrome1(head) + " | ");System.out.print(isPalindrome2(head) + " | ");System.out.println(isPalindrome3(head) + " | ");printLinkedList(head);System.out.println("=========================");head = new Node(1);head.next = new Node(2);head.next.next = new Node(3);head.next.next.next = new Node(2);head.next.next.next.next = new Node(1);printLinkedList(head);System.out.print(isPalindrome1(head) + " | ");System.out.print(isPalindrome2(head) + " | ");System.out.println(isPalindrome3(head) + " | ");printLinkedList(head);System.out.println("=========================");}}
將單鏈表按照給定的數(shù)值,劃分成左邊小、中間相等、右邊大的形式
思路
- 1,申請一個鏈表長度大小一致的數(shù)組,然后遍歷鏈表的過程中,將每一個點(diǎn)放到數(shù)組容器中,在數(shù)組里面進(jìn)行荷蘭國旗問題,再把數(shù)組容器中的元素都串聯(lián)起來,形成一個鏈表返回
- 2,保證穩(wěn)定性:根據(jù)題目要求設(shè)置三個區(qū),小于區(qū)、等于區(qū)和大于區(qū),每個區(qū)間包含兩個變量,開始節(jié)點(diǎn)和結(jié)尾節(jié)點(diǎn),一共設(shè)置6個變量,6個變量都指向null;當(dāng)遇到第一個元素3的時候,它是小于指定元素5的,將小于區(qū)域的開始和結(jié)束指針都指向3;第二個元素是5,屬于等于區(qū),讓等于區(qū)的start和end都指向第二個元素5;第3個元素也是5,讓等于區(qū)的end只想第三個元素。以此類推,得到上面的結(jié)果。最后將小于區(qū)域的end指針鏈接等于區(qū)域的start指針,等于區(qū)域的end指針鏈接大于區(qū)域的start指針。需要注意的是,有可能上面6個變量有不存在的情形,需要仔細(xì)判別。
兩個單鏈表相交的一系列問題
- 給定兩個可能有環(huán)也可能無環(huán)的單鏈表,頭節(jié)點(diǎn)head1和head2,實(shí)現(xiàn)一個函數(shù),如果兩個鏈表相交,返回相交的第一個節(jié)點(diǎn),如果不相交,返回null
- 兩個鏈表的長度之和為N,時間復(fù)雜度為O(N),額外空間復(fù)雜度為O(1)
- 相交:共用內(nèi)存地址??
- 有環(huán)/無環(huán):寫一個函數(shù),輸入的類型是鏈表的頭節(jié)點(diǎn),判斷是否有環(huán),以及返回第一個有環(huán)的節(jié)點(diǎn)。使用集合來做,遍歷鏈表,每遍歷一個元素,將其放入到集合中,判定是否存在此元素,如果將一個元素放入集合中,發(fā)現(xiàn)他已經(jīng)存在,則是有環(huán)的,并且他就是第一個入環(huán)節(jié)點(diǎn)。
- 使用快慢指針來做,快指針每次移動倆個位置,慢指針每次移動一個位置,當(dāng)快慢指針第一次相交之后,快指針回到鏈表的起始點(diǎn),慢指針呆在原地不動。然后快指針和慢指針都每次移動一個位置,當(dāng)他們再次相遇之后,相遇的元素就是入環(huán)的第一個元素,且能證明這個鏈表是有環(huán)的結(jié)構(gòu)。上圖所示的是環(huán)外4個點(diǎn),環(huán)內(nèi)4個點(diǎn),可以按照這個流程走一遍。
- 兩個無環(huán)鏈表相交問題,哪個鏈表長,先走比短鏈表多余的部分,然后一起走,只要有一點(diǎn)的內(nèi)存地址相穩(wěn)合,則代表兩者相交。
- 如果一個是有環(huán)的,一個是無環(huán)的,那么他倆一定不相交
- 如果兩者都是環(huán)狀結(jié)構(gòu),那么可以劃分為上面三種形式。1,兩者都是環(huán),都不相交;2,兩者共用環(huán),卻已經(jīng)在環(huán)外相交,入環(huán)點(diǎn)一樣;3,共用環(huán),但是接入環(huán)的點(diǎn)不一樣。
- 第一種情形,如上圖的左邊的圖形“6”,loop1為相交點(diǎn),讓loop1順著next指針走一圈,如果走了一圈沒有遇到loop2,則二者不相交。
- 第二種類型,只需要判斷二者的入環(huán)節(jié)點(diǎn)是否一致,就可以判定是否相交。如果需要判斷相交的第一個節(jié)點(diǎn),入環(huán)點(diǎn)作為終止節(jié)點(diǎn),轉(zhuǎn)化為先前的長短鏈,找相交點(diǎn)。
- 第一種情形,如上圖的右邊的圖形所示,loop1為左邊的相交點(diǎn),loop2為右邊的相交點(diǎn),讓loop1順著next指針走一圈,如果走了一圈遇到loop2,則二者相交。loop1 和loop2都是相交節(jié)點(diǎn),只不過loop1距離鏈表1更近,loop2距離鏈表2更近。
package class04;public class Code07_FindFirstIntersectNode {public static class Node {public int value;public Node next;public Node(int data) {this.value = data;}}public static Node getIntersectNode(Node head1, Node head2) {if (head1 == null || head2 == null) {return null;}Node loop1 = getLoopNode(head1);Node loop2 = getLoopNode(head2);if (loop1 == null && loop2 == null) {return noLoop(head1, head2);}if (loop1 != null && loop2 != null) {return bothLoop(head1, loop1, head2, loop2);}return null;}// 找到鏈表第一個入環(huán)節(jié)點(diǎn),如果無環(huán),返回nullpublic static Node getLoopNode(Node head) {if (head == null || head.next == null || head.next.next == null) {return null;}Node n1 = head.next; // n1 -> slowNode n2 = head.next.next; // n2 -> fastwhile (n1 != n2) {if (n2.next == null || n2.next.next == null) {return null;}n2 = n2.next.next;n1 = n1.next;}n2 = head; // n2 -> walk again from headwhile (n1 != n2) {n1 = n1.next;n2 = n2.next;}return n1;}// 如果兩個鏈表都無環(huán),返回第一個相交節(jié)點(diǎn),如果不想交,返回nullpublic static Node noLoop(Node head1, Node head2) {if (head1 == null || head2 == null) {return null;}Node cur1 = head1;Node cur2 = head2;int n = 0;while (cur1.next != null) {n++;cur1 = cur1.next;}while (cur2.next != null) {n--;cur2 = cur2.next;}if (cur1 != cur2) {return null;}// n? :? 鏈表1長度減去鏈表2長度的值cur1 = n > 0 ? head1 : head2; // 誰長,誰的頭變成cur1cur2 = cur1 == head1 ? head2 : head1; // 誰短,誰的頭變成cur2n = Math.abs(n);while (n != 0) {n--;cur1 = cur1.next;}while (cur1 != cur2) {cur1 = cur1.next;cur2 = cur2.next;}return cur1;}// 兩個有環(huán)鏈表,返回第一個相交節(jié)點(diǎn),如果不想交返回nullpublic static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {Node cur1 = null;Node cur2 = null;if (loop1 == loop2) {cur1 = head1;cur2 = head2;int n = 0;while (cur1 != loop1) {n++;cur1 = cur1.next;}while (cur2 != loop2) {n--;cur2 = cur2.next;}cur1 = n > 0 ? head1 : head2;cur2 = cur1 == head1 ? head2 : head1;n = Math.abs(n);while (n != 0) {n--;cur1 = cur1.next;}while (cur1 != cur2) {cur1 = cur1.next;cur2 = cur2.next;}return cur1;} else {cur1 = loop1.next;while (cur1 != loop1) {if (cur1 == loop2) {return loop1;}cur1 = cur1.next;}return null;}}public static void main(String[] args) {// 1->2->3->4->5->6->7->nullNode head1 = new Node(1);head1.next = new Node(2);head1.next.next = new Node(3);head1.next.next.next = new Node(4);head1.next.next.next.next = new Node(5);head1.next.next.next.next.next = new Node(6);head1.next.next.next.next.next.next = new Node(7);// 0->9->8->6->7->nullNode head2 = new Node(0);head2.next = new Node(9);head2.next.next = new Node(8);head2.next.next.next = head1.next.next.next.next.next; // 8->6System.out.println(getIntersectNode(head1, head2).value);// 1->2->3->4->5->6->7->4...head1 = new Node(1);head1.next = new Node(2);head1.next.next = new Node(3);head1.next.next.next = new Node(4);head1.next.next.next.next = new Node(5);head1.next.next.next.next.next = new Node(6);head1.next.next.next.next.next.next = new Node(7);head1.next.next.next.next.next.next = head1.next.next.next; // 7->4// 0->9->8->2...head2 = new Node(0);head2.next = new Node(9);head2.next.next = new Node(8);head2.next.next.next = head1.next; // 8->2System.out.println(getIntersectNode(head1, head2).value);// 0->9->8->6->4->5->6..head2 = new Node(0);head2.next = new Node(9);head2.next.next = new Node(8);head2.next.next.next = head1.next.next.next.next.next; // 8->6System.out.println(getIntersectNode(head1, head2).value);}}
?
總結(jié)
以上是生活随笔為你收集整理的算法入门篇五 链表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。