演算法題010 -- [判斷一個單鏈表是否是迴文連結串列] by java
阿新 • • 發佈:2018-12-21
題目
判斷一個單鏈表是否是迴文連結串列。
如:[1, 2, 3, 2, 1] 就是一個迴文連結串列,正著依次看連結串列中元素和反著依次看連結串列中元素都是一樣的。
要求:
時間複雜度 O(n) 空間複雜度 O(1)
程式碼
package algorithm010;
import algorithm006.ListNode;
public class Algorithm010 {
public static void main(String[] args) {
System.out.println(isPalindromeLinkedList(getListNode1()));
System. out.println(isPalindromeLinkedList2(getListNode2()));
}
/**方法一
* 思路:特殊值記錄 + 單鏈反轉
* 在空間複雜度是O(1)的限制下
* 可以使用一個變數在遍歷連結串列的過程中,sun += 該節點所對應的值,
* 需要設計的技巧在於這個值必須是特殊唯一的值
* 如演算法中,我設定的對應的值就是用 sum = content * pos
* 如果連結串列是迴文連結串列,那麼從連結串列的最後一個元素反著來,依次減去節點相應的值
* 那麼最後 sum 必然迴歸於 0,否則該連結串列就不是一個迴文連結串列。
* 那麼就在反轉連結串列的遍歷中,處理 sum 值的疊加
* 優點:思路比較清晰,簡單,時間複雜度 O(2n),其實就是 O(n),只不過是要與方法二有個比較
* 缺點:這個方法適用於content是整數的情況,如果是一個字串,就不太合適了
*
* @param listNode
* @return
*/
public static boolean isPalindromeLinkedList(ListNode listNode) {
long sum = 0;
long factor = 1;
ListNode pre = null;
ListNode headNode = null;
while(listNode != null) {
sum += listNode.content * factor;
factor ++;
ListNode tempNext = listNode.next;
listNode.next = pre;
pre = listNode;
if(null == tempNext)
headNode = listNode;
listNode = tempNext;
}
factor = 1;
while(headNode != null) {
sum -= headNode.content * factor;
factor ++;
headNode = headNode.next;
}
return sum == 0;
}
/**方法二
* 思路:尋找中間節點,然後反轉從中間節點後的連結串列,再與之前的連結串列比較
* 比較:遍歷中間節點的過程中,同時遍歷前半部分連結串列
* 如果在同一個迴圈中出現兩個連結串列的content不同,那麼就不成立是迴文連結串列
* 注意:因為遍歷的是後半部分反轉後的連結串列,所以必須保證後半部分反轉生成的連結串列長度必須不大於前半部分
* 難點1:如果尋找中間節點
* 在程式碼中利用了兩種方式尋找中間節點,見 getMiddleHeadNodeBy2Length、getMiddleHeadNodeBy2Pointer
* 難點2:如果保證後半部分的節點的長度不大於前半部分
* 這裡其實用實際連結串列來形容就是:
* 在 【0,1,2,3,2,1,0】,必須返回後半部分的節點 2
* 在 【0,1,2,3,3,2,1,0】,必須返回後半部分的節點 3
* 優點:getMiddleHeadNodeBy2Length 方法下 時間複雜度 O(2n)
* getMiddleHeadNodeBy2Pointer 方法下 時間複雜度 O(3/2n)
* 適用於所有連結串列
*
* @param listNode
* @return
*/
public static boolean isPalindromeLinkedList2(ListNode listNode) {
// ListNode middleHeadNode = getMiddleHeadNodeBy2Length(listNode);
ListNode middleHeadNode = getMiddleHeadNodeBy2Pointer(listNode);
System.out.println(middleHeadNode.toString());
ListNode reverseLinkedList = reverseLinkedList(middleHeadNode, null);
System.out.println(reverseLinkedList.toString());
while(reverseLinkedList != null) {
if(listNode.content != reverseLinkedList.content) {
return false;
}
listNode = listNode.next;
reverseLinkedList = reverseLinkedList.next;
}
return true;
}
/**
* 遞迴反轉連結串列
* @param listNode
* @param pre
* @return
*/
private static ListNode reverseLinkedList(ListNode listNode, ListNode pre) {
if(listNode.next == null) {
listNode.next = pre;
return listNode;
}
ListNode tempNode = listNode.next;
listNode.next = pre;
pre = listNode;
listNode = tempNode;
return reverseLinkedList(listNode, pre);
}
/**
* 利用長度尋找中間節點
* @param listNode
* @return
*/
public static ListNode getMiddleHeadNodeBy2Length(ListNode listNode) {
int step = (int) Math.ceil(getLinkedListLength(listNode)/2f);//保證返回的是中間節點的座標
//提前給 temp賦值,其實就是保證在下面的遍歷結束後,temp返回的總是比中間節點前進一位
ListNode temp = listNode;
while(step > 0) {
if(null == temp)
temp = listNode;
else
temp = temp.next;
step --;
}
return temp;
}
/**
* 雙指標尋找中間節點
* @param listNode
* @return
*/
public static ListNode getMiddleHeadNodeBy2Pointer(ListNode listNode) {
ListNode slowPointer = listNode;
ListNode fastPointer = listNode.next;
if(null == fastPointer)
return slowPointer;
while(slowPointer != null && fastPointer != null) {
slowPointer = slowPointer.next;
if(null == fastPointer.next) {
break;
}
fastPointer = fastPointer.next.next;
}
return slowPointer;
}
/**
* 獲取連結串列長度
*
* @param listNode
* @return
*/
public static float getLinkedListLength(ListNode listNode) {
float length = 0;
while(listNode != null) {
length ++;
listNode = listNode.next;
}
return length;
}
public static ListNode getListNode1() {
ListNode listNode2 = new ListNode(0);
ListNode listNode4 = new ListNode(1);
ListNode listNode6 = new ListNode(2);
ListNode listNode8 = new ListNode(3);
ListNode listNode10 = new ListNode(3);
ListNode listNode11 = new ListNode(2);
ListNode listNode12 = new ListNode(1);
ListNode listNode13 = new ListNode(0);
listNode2.next = listNode4;
listNode4.next = listNode6;
listNode6.next = listNode8;
listNode8.next = listNode10;
listNode10.next = listNode11;
listNode11.next = listNode12;
listNode12.next = listNode13;
return listNode2;
}
public static ListNode getListNode2() {
ListNode listNode2 = new ListNode(0);
ListNode listNode4 = new ListNode(1);
ListNode listNode6 = new ListNode(2);
ListNode listNode8 = new ListNode(3);
ListNode listNode10 = new ListNode(2);
ListNode listNode11 = new ListNode(1);
ListNode listNode12 = new ListNode(0);
listNode2.next = listNode4;
listNode4.next = listNode6;
listNode6.next = listNode8;
listNode8.next = listNode10;
listNode10.next = listNode11;
listNode11.next = listNode12;
return listNode2;
}
}