题目
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2 输出: false 示例 2:
输入: 1->2->2->1 输出: true
思路
方法一:数组模拟
比较直接的方法,就是把链表转成数组,然后判断是否是回文
java代码如下:
class Solution {
public boolean isPalindrome(ListNode head){
int len = 0;
ListNode cur = head;
//记录链表长度
while(cur != null){
cur = cur.next;
len++;
}
cur = head;//重新指向头结点
int[] res = new int[len];
//将元素加到数组中
for(int i = 0; i < res.length; i++){
res[i] = cur.val;
cur = cur.next;
}
//比较数组中是否是回文
for(int i = 0, j = len - 1; i < j; i++,j--){//这里i <= j 或者 i < j都可以
if(res[i] != res[j]){
return false;
}
}
return true;
}
}
方法二:快慢指针(反转后半部分链表)
分为以下几步:
- 首先用快慢指针找到中间位置:即快指针走两步,慢指针走一步,快指针遇到终止位置时,慢指针就在链表中间位置
- 同时用
pre
记录慢指针指向节点的前一个节点,用来分割链表 - 将链表分为前后均等两部分,如果链表长度是奇数,那么后半部分多一个节点
- 将后半部分反转 ,得
cur2
,前半部分为cur1
- 按照
cur1
的长度,依次比较cur1
和cur2
的节点数值
java代码如下:
class Solution {
public boolean isPalindrome(ListNode head){
// 如果为空或者仅有一个节点,返回true
if(head == null && head.next == null){
return true;
}
ListNode slow = head;
ListNode fast = head;
ListNode pre = head;
while(fast != null && fast.next != null){
pre = slow;// 记录slow的前一个结点
slow = slow.next;
fast = fast.next.next;
}
//分割链表的时候,一定要确定中间节点(slow指向的节点)包含在哪部分中,这里是将中间节点包含在右半部分
pre.next = null;//分割成两个链表,中间节点包含在右半部分
// 前半部分
ListNode cur1 =head;
// 后半部分,使用反转链表
ListNode cur2 = reverseList(slow);
while(cur1 != null){//因为中间节点包含在右半部分。所以前半部分链表长度一定小于等于后半部分链表,所以从cur1开始遍历即可
if(cur1.val != cur2.val){
return false;
}
//同时后移
cur1 = cur1.next;
cur2 = cur2.next;
}
return true;
}
//反转链表逻辑
ListNode reverseList(ListNode node){
ListNode tmp = null;//保存下一个节点
ListNode cur = node;//指向当前节点
ListNode pre = null;//指向当前节点前驱节点
while(cur != null){
tmp = cur.next;//保存下一个节点
cur.next = pre;//将当前节点指向前驱节点
//同时后移,继续操作
pre = cur;
cur = tmp;
}
return pre;//因为pre走到最后就是头结点,cur最终指向null
}
}