先简单了解下:
单链表:
快慢指针:
slow:正常的指针,每次走一步
fast:每次走两步
回文问题:
noon、奥利奥、1221等等这种就是回文
如何用快慢指针解决单链表的回文问题呢?
看到noon 、 奥利奥这样的字眼,我们可以想
以noon为例,我们可以从no on 中间开始,一边往左,一边右,同时去判断,直到结束(遇到null了)
那么怎么找到这个中间位置呢?——快慢指针
为什么快慢指针能找到中间位置呢?——如果走n步的话,s(slow)走了n步,f(fast)走了2n步
这时候如果链表长度刚好为2n,那么s就在中间位置了呀
(这里先埋下个伏笔,链表的长度都一定是2的倍数(偶数)吗,通常遇到2n我们都要去考虑下奇偶数的问题)
那如果要使指针能够往左边走的话,我们是不是需要在原先的链表上逆序?(先不考虑破坏原链表的问题哈,我们这里只要结果)
逆序中我们需要几个指针呢?
1个?——肯定不行
2个?——不够,原因如下:
假设现在我们有这样的链表,s、prev两个指针(先忽略fast)
如果此时,s要完成逆序,需要把s的next指向prev,那会发生什么呢?
这时候可以发现,链表断掉了
那有人说了,我不用prev,我用next,就是这个
如果这是一条很长的链表(1,2,3,4只是中间的某几个点的标注)
那么s如何找到它的前面一个结点呢?——再遍历一遍嘛——当然可以,你有钱任性(不管时间复杂度)
因此我们就选用三个指针好了 ,prev s 和next 这三个,这样就绝对万无一失了(怎么指向我都有原来的指针指着,不会丢)
好了我们确定了用三个指针后,就是实现逆序的过程
第一步:改变s.next的指向
第二步,prev去到s的位置(s准备去next的位置)
(注意这里用的并不是prev.next 中间过程的prev是指向前面的,也就是这样的)
第三步,s去到next的位置(同样不是用s.next过去的哦!s.next现在已经指着1了而不是2)
第四步,next移动到下一个位置(这时候可以用next.next了)
这个逆序的过程其实是在s不断前进直到在中间位置的过程中进行
那怎么到中间位置呢?——靠的是fast来停止而不是slow哦
这是因为f走得快,容易到链表的结尾
刚才埋下的奇偶问题这里f也遇到了
也就是链表长度为奇数偶数时,f所在位置时不同的,同时也决定了要不要给s处理一下(是否再往后走一步,为什么?看下去)
先来看下为奇数为偶数时的s f情况(就先仅仅看s f移动,先不看逆序)
奇数:
偶数:
(f每次走就是 f. next.next)
可以看到到应该停止下来的地方时 奇偶不同 f的位置也不同
就是 奇数:f.next==null 偶数: f==null
这时我们再结合逆序来看下s(之后就是判断回文了,此时需要判断下s的情况)
奇数情况(此时就不再看f了 因为已经找到中间位置了)
可以看到如果需要进行比较的话肯定是prev和s间进行比较,而此时还需要让s走下一步,这样才到开始判断的地方(也就是c并不需要判断),即
不断 判断 和 用next移到各自下一个,直到遇到null
偶数情况:
此时可以看到,不需要对s进行额外的操作就可以开始判断回文
到这里,就全部解析完用快慢指针 解决单链表回文问题
当然解决单链表回文问题还可以用其他方法解决 例如借助堆栈
https://blog.csdn.net/tangli555/article/details/51384296
用快慢指针只是因为我第一次学的时候就是用这个来解决,而且这个相比借助用堆栈也比较难理解一丢丢丢丢丢丢
借鉴代码:
https://www.jianshu.com/p/462fa3e4cd43
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) {
return true;
}
ListNode prev = null;
ListNode slow = head;
ListNode fast = head;
#去找中间位置,同时把前面部分逆序
while (fast != null && fast.next != null) {
fast = fast.next.next;
ListNode next = slow.next;
slow.next = prev;
prev = slow;
slow = next;
}
#这是为奇数时对s额外的操作
if (fast != null) {
slow = slow.next;
}
#开始判断回文
while (slow != null) {
if (slow.val != prev.val) {
return false;
}
slow = slow.next;
prev = prev.next;
}
return true;
}
}