以專題的形式更新刷題貼,歡迎跟我一塊兒學習刷題,相信我,你的堅持,絕對會有意想不到的收穫。每道題會提供簡單的解答,若是你有更優雅的作法,歡迎提供指點,謝謝。ide
注:若是你在看代碼的時候發現代碼排版亂了麻煩告訴我一聲,謝謝。學習
給定一個鏈表的頭節點 head, 請判斷該鏈表是否爲迴文結構。3d
例如:指針
1->2->1,返回 true.code
1->2->2->1, 返回 true。blog
1->2->3,返回 false。it
若是鏈表的長度爲 N, 時間複雜度達到 O(N)。ast
普通解法:士:★☆☆☆class
進階解法:尉:★★☆☆進階
方法1
咱們能夠利用棧來作輔助,把鏈表的節點所有入棧,在一個一個出棧與鏈表進行對比,例如對於鏈表 1->2->3->2->2,入棧後如圖:
而後再逐一出棧與鏈表元素對比。
這種解法比較簡單,時間複雜度爲 O(n), 空間複雜度爲 O(n)。
1//方法1 2public static boolean f1(Node head) { 3 if (head == null || head.next == null) { 4 return true; 5 } 6 Node temp = head; 7 Stack<Node> stack = new Stack<>(); 8 while (temp != null) { 9 stack.push(temp); 10 temp = temp.next; 11 } 12 while (!stack.isEmpty()) { 13 Node t = stack.pop(); 14 if (t.value != head.value) { 15 return false; 16 } 17 head = head.next; 18 } 19 return true; 20}
真的須要所有入棧嗎?其實咱們也能夠讓鏈表的後半部分入棧就能夠了,而後把棧中的元素與鏈表的前半部分對比,例如 1->2->3->2->2 後半部分入棧後如圖:
而後逐個出棧,與鏈表的前半部分(1->2)對比。這樣作的話空間複雜度會減小一半。
代碼以下:
1//方法2 2public static boolean f(Node head) { 3 if(head == null || head.next == null) 4 return true; 5 Node slow = head;//慢指針 6 Node fast = head;//快指針 7 Stack<Node> stack = new Stack<>(); 8 //slow最終指向中間節點 9 while (fast.next != null && fast.next.next != null) { 10 slow = slow.next; 11 fast = fast.next.next; 12 } 13 System.out.println(slow.value); 14 slow = slow.next; 15 while (slow != null) { 16 stack.push(slow); 17 slow = slow.next; 18 } 19 //進行判斷 20 while (!stack.isEmpty()) { 21 Node temp = stack.pop(); 22 if (head.value != temp.value) { 23 return false; 24 } 25 head = head.next; 26 } 27 return true; 28}
方法三:空間複雜度爲 O(1)。
上道題咱們有做過鏈表的反轉的,沒看過的能夠看一下勒:【鏈表問題】如何優雅着反轉單鏈表],咱們能夠把鏈表的後半部分進行反轉,而後再用後半部分與前半部分進行比較就能夠了。這種作法額外空間複雜度只須要 O(1), 時間複雜度爲 O(n)。
代碼以下:
1//方法3 2public static boolean f2(Node head) { 3 if(head == null || head.next == null) 4 return true; 5 Node slow = head;//慢指針 6 Node fast = head;//快指針 7 //slow最終指向中間節點 8 while (fast.next != null && fast.next.next != null) { 9 slow = slow.next; 10 fast = fast.next.next; 11 } 12 Node revHead = reverse(slow.next);//反轉後半部分 13 //進行比較 14 while (revHead != null) { 15 System.out.println(revHead.value); 16 if (revHead.value != head.value) { 17 return false; 18 } 19 head = head.next; 20 revHead = revHead.next; 21 } 22 return true; 23} 24//反轉鏈表 25private static Node reverse(Node head) { 26 if (head == null || head.next == null) { 27 return head; 28 } 29 Node newHead = reverse(head.next); 30 head.next.next = head; 31 head.next = null; 32 return newHead; 33}
思考:若是給你的是一個環形鏈表,而且指定了頭節點,那麼該如何判斷是否爲迴文鏈表呢?
無
無
未知。
無。此題爲開放題,你能夠根據這個設定各類其餘要求條件。
【鏈表問題】環形單鏈表約瑟夫問題
【鏈表問題】如何優雅着反轉單鏈表
【鏈表問題】刪除單鏈表的中間節點
【鏈表問題】刪除單鏈表中的第K個節點