现在当前节点【cur】已经指向【2】,那它的下个节点就是【1】,如下图所示。
经过上面的两步循环,成功的将指针进行了反转,剩下的节点循环也就如出一辙了。
当循环到最后节点【5】时,下个节点为null,此时结束while循环,而节点【5】也是指向了上一个节点【4】。
最后我们再看下运行结果。
二,回文链表 1.2.1 题目分析如果做过字符串的算法题,里面有个回文字符串的题目。没错,它俩的意思是一样的。
看题目描述得知一个链表是不是回文链表,就是看链表就是看链表正读和反读是不是一样的。
假如说,我们拿到了后半部分链表,再将其反转。去和链表的前半部分比较,值相等就是回文链表了。
注意:
这种方式会破坏原链表的结构,为保证题目的一致性,最后再将链表再重新拼接
另外一种解题方式为:将整个链表节点遍历保存到数组中,而数组是有下标,并可以直接获取数组的大小,那么只需从数组的首尾去判断即可
反转链表上一道题我们已经分享了,现在重点是如何获取后半部分的链表。
我们再说说快慢指针的思想,通常我们定义2个指针,一个移动快,一个移动慢。详细的案例可以参考本人上一篇文章《开启算法之路,还原题目,用debug调试搞懂每一道题》,有一道关于快慢指针的题目。
定义慢指针每次移动1个节点,快指针每次移动2个节点,当然我们是需要保证快节点的下下个个节点不为空。
slow = slow.next; fast = fast.next.next;其实快慢指针的思想就是,假设链表是一个回文链表,快指针比慢指针是多走一步,当快指针走完的时候,慢指针也就刚好走到该链表的一半。
上图中slow指针正好走到链表的一半,此时也就得到链表的后半部分了,即slow.next。
1.2.2 代码分析老套路,先创建一个回文链表。
ListNode l1 = new ListNode(1); ListNode l2 = new ListNode(2); ListNode l3 = new ListNode(2); ListNode l4 = new ListNode(1); NodeFun nodeFun = new NodeFun(); nodeFun.add(l1); nodeFun.add(l2); nodeFun.add(l3); ListNode head = nodeFun.add(l4);获取后半部分链表代码。
private ListNode endOfFirstHalf(ListNode head) { ListNode fast = head; ListNode slow = head; while (fast.next != null && fast.next.next != null) { fast = fast.next.next; slow = slow.next; } return slow; }反转链表的代码与上题目是一样的。
最后将两个链表进行判断是否是一样的。
// 判断是否回文 ListNode p1 = head; ListNode p2 = secondHalfStart; boolean flag = true; while (flag && p2 != null) { if (p1.val != p2.val) { flag = false; } p1 = p1.next; p2 = p2.next; } 1.2.3 debug调试先获取链表的后半部分。
debug开始循环后,fast直接走到链表的第3个节点【2】
slow.next就是链表的后半部分,再将后半部分进行链表反转
最后我们也就得到如下2个链表。
最后将这2个链表进行比较是否相等,相等则是回文链表。
三,链表的中间节点 1.3.1 题目分析