微软和谷歌的几个大佬组织了一个面试刷题群,可以加管理员VX:sxxzs3998(备注优快云),进群参与讨论和直播
1.题目
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2 输出: false
示例 2:
输入: 1->2->2->1 输出: true
进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
2.解析
1、先通过「双指针技巧」中的快慢指针来找到链表的中点:
ListNode slow, fast;
slow = fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// slow 指针现在指向链表中点
2、如果fast
指针没有指向null
,说明链表长度为奇数,slow
还要再前进一步:
if (fast != null)
slow = slow.next;
3、从slow
开始反转后面的链表,现在就可以开始比较回文串了:
ListNode left = head;
ListNode right = reverse(slow);
while (right != null) {
if (left.val != right.val)
return false;
left = left.next;
right = right.next;
}
return true;
至此,把上面 3 段代码合在一起就高效地解决这个问题了,其中reverse
函数很容易实现:
ListNode reverse(ListNode head) {
ListNode pre = null, cur = head;
while (cur != null) {
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
算法总体的时间复杂度 O(N),空间复杂度 O(1),已经是最优的了。
完整代码:
class Solution { //快慢指针,反转链表
public boolean isPalindrome(ListNode head) {
//快慢指针寻找链表中点
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
//slow指针指向后半段的开头
if(fast != null) slow = slow.next;
//前半段的开头left
ListNode left = head;
//反转链表后后半段的开头right
ListNode right = reverse(slow);
//判断是否回文
while(right != null){
if(left.val != right.val) return false;
left = left.next;
right = right.next;
}
return true;
}
//反转后半段链表,参数是后半段的开头,即slow指针
public ListNode reverse(ListNode node){
ListNode pre = null;
ListNode cur = node;
ListNode nex = node;
while(cur != null){
nex = cur.next;
cur.next = pre;
pre = cur;
cur = nex;
}
//返回反转后后半段的开头,即反转前链表的最后一个节点
return pre;
}
}
微软和谷歌的几个大佬组织了一个面试刷题群,可以加管理员VX:sxxzs3998(备注优快云),进群参与讨论和直播