編寫函數,檢查鏈表是否爲迴文

 

題解:java

判斷一個鏈表是否是迴文的,這裏要求O(n)時間複雜度和O(1)的空間時間複雜度,總共想了三種辦法,三種辦法都用到了兩個指針,符合題目要求的只有最後一種。node

 

第一種辦法:用數組倒着存前半段的鏈表的值,而後和後半段鏈表的值進行比較。這種解法運行的時間最久多是由於數組倒着插入比較耗時。數組

代碼:數據結構

 

[java] view plain copyapp

 

  1. //用數組實現 o(n/2)空間  
  2.      public static boolean isPalindrome(ListNode head) {  
  3.           
  4.         // ArrayList<Integer> nodeVal=new ArrayList<>();  
  5.          LinkedList<Integer> nodeVal=new LinkedList<>();  
  6.            
  7.          if(head==null||head.next==null)  
  8.              return true;  
  9.          ListNode slow=head;  
  10.          ListNode fast=head;  
  11.            
  12.          nodeVal.add(0,slow.val);  
  13.          while(fast.next!=null&&fast.next.next!=null)  
  14.          {  
  15.              fast=fast.next.next;  
  16.              slow=slow.next;  
  17.              nodeVal.add(0,slow.val);  
  18.          }  
  19.            
  20.          ListNode cur=slow;  
  21.          if(fast.next!=null)//鏈表長度爲偶數  
  22.              cur=slow.next;  
  23.          int i=0;  
  24.          while(cur!=null)  
  25.          {  
  26.              if(nodeVal.get(i)!=cur.val)  
  27.                  return false;  
  28.              cur=cur.next;  
  29.              i++;  
  30.          }  
  31.          return true;  
  32.         }  
  33.        

第二種解法:在第一種的思路的基礎上,咱們要實現一個倒序,咱們幹嗎不用現成的數據結構-棧,因而把鏈表前半段壓棧,而後出棧和後面的鏈表依次比較,這種運行時間最短,但由於用到了棧仍是不符合題目要求。函數

 

代碼:ui

 

[java] view plain copyspa

 

  1. //用棧實現  
  2.  public static boolean isPalindrome2(ListNode head) {  
  3.        
  4.      Stack<ListNode> stack=new Stack<>();  
  5.      ListNode slow=head;  
  6.      ListNode fast=head;  
  7.        
  8.      if(fast==null||fast.next==null)//0個節點或是1個節點  
  9.          return true;  
  10.   
  11.      stack.push(slow);  
  12.      while(fast.next!=null&&fast.next.next!=null)  
  13.      {  
  14.           
  15.          fast=fast.next.next;  
  16.          slow=slow.next;  
  17.          stack.push(slow);  
  18.      }  
  19.      if(fast.next!=null)//鏈表長度爲偶數  
  20.          slow=slow.next;  
  21.        
  22.      ListNode cur=slow;  
  23.      while(cur!=null)  
  24.      {  
  25.          if(cur.val!=stack.pop().val)  
  26.              return false;  
  27.          cur=cur.next;  
  28.      }  
  29.      return true;  
  30.    
  31.  }  


第三種:咱們這樣想,咱們可不能夠不借助外在的存儲實現倒序呢,實際上是能夠的,鏈表反轉的時候咱們就沒有藉助外在存儲。思路是把後半段的原地鏈表反轉而後和前半段進行比較(固然你也能夠反轉前半段)運行時間稍微比第二種慢一些,可是符合題目O(1)空間複雜度的要求.net

 

代碼:指針

 

[java] view plain copy

 

  1. //鏈表原地轉置實現o(1)空間複雜度  
  2. public static boolean isPalindrome3(ListNode head) {  
  3.  ListNode slow=head;  
  4.  ListNode fast=head;  
  5.    
  6.  if(fast==null||fast.next==null)//0個節點或是1個節點  
  7.      return true;  
  8.   
  9.   
  10.  while(fast.next!=null&&fast.next.next!=null)  
  11.  {  
  12.      fast=fast.next.next;  
  13.      slow=slow.next;  
  14.  }  
  15.  //對鏈表後半段進行反轉  
  16.  ListNode midNode=slow;  
  17.  ListNode firNode=slow.next;//後半段鏈表的第一個節點  
  18.  ListNode cur=firNode.next;//插入節點從第一個節點後面一個開始  
  19.  firNode.next=null;//第一個節點最後會變最後一個節點  
  20.  while(cur!=null)  
  21.  {  
  22.      ListNode nextNode=cur.next;//保存下次遍歷的節點  
  23.      cur.next=midNode.next;  
  24.      midNode.next=cur;  
  25.      cur=nextNode;  
  26.  }  
  27.    
  28.  //反轉以後對先後半段進行比較  
  29.  slow=head;  
  30.  fast=midNode.next;  
  31.  while(fast!=null)  
  32.  {  
  33.      if(fast.val!=slow.val)  
  34.          return false;  
  35.      slow=slow.next;  
  36.      fast=fast.next;  
  37.  }  
  38.  return true;  
  39.    
  40. }  

快行指針找到鏈表中間結點

1. 反轉前半部分看是否和後半部分同樣

2. 將前半部分入棧,迭代訪問剩下的一半結點,每次的棧頂元素同樣則是迴文鏈表

 

 

[java] view plain copy

 

  1. import java.util.Stack;  
  2. public class isHuiWen {  
  3.     public boolean isPalinddrome(LinkedListNode head) {  
  4.         LinkedListNode fast = head;  
  5.         LinkedListNode slow = head;  
  6.           
  7.         Stack<Integer> stack = new Stack<Integer>();  
  8.           
  9.         while( fast != null && fast.next != null ) {  
  10.             stack.push(slow.data);  
  11.             slow = slow.next;  
  12.             fast = fast.next.next;  
  13.         }  
  14.           
  15.         //若是鏈表有奇數個元素,那麼fast這時不爲空,則比較後半段時跳過中間元素  
  16.         if ( fast != null ) {  
  17.             slow = slow.next;  
  18.         }  
  19.           
  20.         while (slow != null) {  
  21.             int top = stack.pop().intValue();  
  22.             //若是不相同,則不是迴文  
  23.             if (top != slow.data) {  
  24.                 return false;  
  25.             }  
  26.             slow= slow.next;  
  27.         }  
  28.         return true;  
  29.     }  
  30. }  


 

遞歸的解法:

 

[java] view plain copy

 

  1. class Result{  
  2.     public LinkedListNode node;  
  3.     public boolean result;  
  4. }  
  5.   
  6. Result isPalindromeRecurse(LinkedListNode head, int length) {  
  7.     if (head == null || length == 0) {  
  8.         return new Result(null, true);  
  9.     }  
  10.     else if(length == 1) {  
  11.         return new Result(head.next,true);  
  12.     }  
  13.     else if(length == 2) {  
  14.         return new Result(head.next.next, head.data == head.next.data);  
  15.     }  
  16.     Result res = isPalindromeRecurse(head.next, length -2);  
  17.     if(!res.result || res.node == null){  
  18.         return res;  
  19.     }  
  20.     else{  
  21.         res.result = head.data == res.node.data;  
  22.         res.node = res.node.next;  
  23.         return res;  
  24.     }  
  25. }  
  26.   
  27. boolean isPalinddrome(LinkedListNode head) {  
  28.     Result p = isPalindromeRecurse(head, listSize(head));  
  29.     return p.result;  

思路:

1 Iterative,利用棧,把鏈表前半段存入棧,再逐個彈棧和鏈表後半段比較。注意鏈表長度爲奇數的狀況!要跳過中間節點!

2 遞歸!

定義遞歸函數爲 Result rec(LinkedListNode head, int length)  意義爲 傳入鏈表頭結點和鏈表長度,返回該鏈表的尾節點的下一個節點

Result是一個Wrapper 類,包含了node和當前是否match的判斷

遞歸的關鍵是要清楚遞歸函數的每個參數的意義是什麼,還有返回值的意義是什麼!!!

以下圖:假設在遞歸的某一個階段,要比較前半段的那個1和後半段的那個1是否相等:

根據遞歸能夠獲得藍色部分的返回值Result,包含了一個res.node和match值。res.node的意義就是該子鏈表的尾節點的下一個節點,即後半段的1!

而後咱們能夠把head指向的1和res.node指向的1比較。若是相同則設置match爲true,而且更新本層遞歸(紅色區域)的返回值爲本層子鏈表的尾節點(1)的下一個節點(0),做爲res.node返回。

 

 

 

[java] view plain copy

在CODE上查看代碼片派生到個人代碼片

  1. package LinkLists;  
  2.   
  3. import java.util.Stack;  
  4.   
  5. import CtCILibrary.LinkedListNode;  
  6.   
  7. public class S2_7 {  
  8.   
  9.     // 利用棧,把鏈表前半段存入棧,再逐個彈棧和鏈表後半段比較  
  10.     public static boolean isPalindrome(LinkedListNode head) {  
  11.         LinkedListNode fast = head;  
  12.         LinkedListNode slow = head;  
  13.   
  14.         Stack<Integer> stack = new Stack<Integer>();  
  15.   
  16.         while (fast != null && fast.next != null) {  
  17.             stack.push(slow.data);  
  18.             slow = slow.next;  
  19.             fast = fast.next.next;  
  20.         }  
  21.   
  22.         if (fast != null) { // 只有當鏈表長度爲奇數時,fast纔不會爲null  
  23.             slow = slow.next; // 這時要跳過中間節點  
  24.         }  
  25.   
  26.         while (slow != null) { // 邊彈棧邊比較  
  27.             int top = stack.pop().intValue();  
  28.             if (top != slow.data) {  
  29.                 return false;  
  30.             }  
  31.             slow = slow.next;  
  32.         }  
  33.         return true;  
  34.     }  
  35.   
  36.     // 遞歸  
  37.     public static boolean isPalindrome2(LinkedListNode head) {  
  38.         int size = 0;  
  39.         LinkedListNode n = head;  
  40.         while (n != null) {  
  41.             size++;  
  42.             n = n.next;  
  43.         }  
  44.         Result p = rec(head, size);  
  45.         return p.match;  
  46.     }  
  47.   
  48.     // 傳入鏈表頭結點和鏈表長度,返回該鏈表的尾節點的下一個節點  
  49.     public static Result rec(LinkedListNode head, int length) {  
  50.         if (head == null || length == 0) {  // 空鏈表,確定是迴文  
  51.             return new Result(null, true);  
  52.         } else if (length == 1) {       // 只有1個節點,確定是迴文  
  53.             return new Result(head.next, true);  
  54.         } else if (length == 2) {       // 有兩個節點,若是相同則是迴文  
  55.             return new Result(head.next.next, head.data == head.next.data);  
  56.         }  
  57.           
  58.         Result res = rec(head.next, length-2);      // 長度縮小2的子鏈表問題,res存放子問題的結果和子鏈表尾節點的下一個節點  
  59.         if(!res.match || res.node==null) {          // 不match  
  60.             return res;  
  61.         } else{  
  62.             res.match = head.data == res.node.data;     // 比較當前節點和尾節點是否相等  
  63.             res.node = res.node.next;                           // 更新返回值,即該鏈表的尾節點的下一個節點  
  64.             return res;  
  65.         }  
  66.     }  
  67.       
  68.     static class Result {  
  69.         public LinkedListNode node;  
  70.         public boolean match;  
  71.         public Result(LinkedListNode n, boolean res) {  
  72.             node = n;  
  73.             match = res;  
  74.         }  
  75.     }  
  76.       
  77.       
  78.     public static void main(String[] args) {  
  79.         int length = 10;  
  80.         LinkedListNode[] nodes = new LinkedListNode[length];  
  81.         for (int i = 0; i < length; i++) {  
  82.             nodes[i] = new LinkedListNode(i >= length / 2 ? length - i - 1 : i, null, null);  
  83.         }  
  84.   
  85.         for (int i = 0; i < length; i++) {  
  86.             if (i < length - 1) {  
  87.                 nodes[i].setNext(nodes[i + 1]);  
  88.             }  
  89.             if (i > 0) {  
  90.                 nodes[i].setPrevious(nodes[i - 1]);  
  91.             }  
  92.         }  
  93. //       nodes[length - 2].data = 9; // Uncomment to ruin palindrome  
  94.   
  95.         LinkedListNode head = nodes[0];  
  96.         System.out.println(head.printForward());  
  97.         System.out.println(isPalindrome2(head));  
  98.     }  
  99.   
相關文章
相關標籤/搜索