目录
环形链表
这样的话如果链表中存在环的话,他们两个一定会相遇,如图所示:
代码如下:
// 环形链表
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode fast = head, show = head;
while(fast != null && fast.next != null) {
fast = fast.next.next;
show = show.next;
if (fast == show) {
return true; // 如果有环的话,他们两个一定能相遇
}
}
return false;
}
}
但这里有一个小细节,在while的循环条件里fast != null这个判断条件不能丢
为啥呢?如图所示:
回文链表
🍑所以我们不妨换个思路,你看如果一个链表是回文链表的话:它是不是正好分成了两个部分,既然我们不能反转整个链表,那么我们能不能对链表的后半部分进行反转,这样如果反转后的后半部分和前半部分是重合的,那么就说明这是一个回文链表。
🍑那么问题又来了?我们怎样把链表分为两部分呢?就是如上图所示只有我们能够找到链表的中间位置3就好。
我们定义两个结点的引用fast和slow,fast每次移动两个结点,slow每次移动一个结点。
能够移动的条件就是:
开始时
结束时
📝总结一下就是:
- 用快慢指针找到中间位置,把代码分为前后两个部分
- 对后半部分进行旋转操作
- 比较前后两个部分是否相等
class Solution {
// 首先要找到中间结点
public ListNode midFind(ListNode slow, ListNode fast) {
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow; // 此时慢指针所指向的就是中间结点
}
// 反转链表,把中间结点之后的结点进行反转
public ListNode reverseList(ListNode cur) {
ListNode pre = null;
while(cur != null) {
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
// 判断前后两部分是否相等
public boolean isPalindrome(ListNode head) {
ListNode dummyHead = new ListNode(0, head); // 设置虚拟头结点,当结点只有较少时方便处理
ListNode mid = midFind(dummyHead, dummyHead); // mid链表的中间结点
// 对中间结点往后的后半部分进行反转
ListNode tail = reverseList(mid.next);
while(dummyHead != mid && head != null && tail != null) {
if (head.val != tail.val) {
return false;
}
head = head.next;
tail = tail.next;
}
return true;
}
}