題目:請判斷一個鏈表是否爲迴文鏈表。
解析:
1.利用棧求解
①首先遍歷鏈表獲取鏈表的長度len;
②根據鏈表的長度,將鏈表的前半部分壓入棧,將後半部分依次與彈棧的元素比較看是否一致,一致則爲迴文鏈表;
③這裏注意的是鏈表的後半部分的開始位置(鏈表長度的奇偶)。
public boolean isPalindrome1(ListNode head) {
if (head == null) return true;
if (head.next == null) return true;//鏈表只有一個的時候
int len = 0;
ListNode first = head;
//鏈表的長度
while (head != null){
head = head.next;
len++;
}
//前半部分壓入棧
Stack<Integer> stack = new Stack<Integer>();
int mid = len/2;
if (len%2 == 0){
while ((mid--)!=0){
stack.push(first.val);
first = first.next;
}
//注意區分mid--和--mid時遍歷停止時的first指向的結點
//鏈表長度是偶數,此時first表示鏈表後半部分的開始
}else{
while ((mid--)!=0){
stack.push(first.val);
first = first.next;
}
first = first.next;
//鏈表長度是奇數,此時first表示鏈表後半部分的開始
}
//後半部分與棧中元素比較
while (first!=null){
if (first.val != stack.pop())
return false;
first = first.next;
}
return true;
}
2.雙指針—鏈表反轉
①定義兩個指針p1和p2,開始同時指向頭結點;
②指針p1和p2同時移動,p1移動一個節點,p2移動兩個結點,當p2移動到鏈表的末尾無法在移動時,此時p1剛好指向鏈表的中間結點;
例:
1->2->2->1 p1停留在第一個結點2上
1->2->3->2->1 p1停留在結點3上
③進行反轉p1後面的部分鏈表操作;
④比較前半部分的鏈表和反轉的後半部分鏈表。(從上述例中明顯可以看出,不區分鏈表的奇偶)
public boolean isPalindrome2(ListNode head) {
if (head == null) return true;
if (head.next == null) return true;
ListNode p1 = head, p2 = head;
//利用快慢指針,將p1移動到鏈表的中間部分
while (p2.next != null && p2.next.next != null){
p1 = p1.next;
p2 = p2.next.next;
}
//反轉此時p1之後的鏈表
//不用考慮鏈表的奇偶
ListNode pre = null, curnode = null, tmpnode = p1.next;
while (tmpnode != null){
curnode = tmpnode.next;
tmpnode.next = pre;
pre = tmpnode;
tmpnode = curnode;
}
p1.next = pre;//接上反轉後的鏈表
//比較前半部分和反轉後的部分是否一致
while(pre != null){
if (head.val != pre.val)
return false;
head = head.next;
pre = pre.next;
}
return true;
}