文章目录
- 1. 寻找链表中倒数第K个节点
- 1.1. 思路分析
- 1.2 代码实现
- 2. 寻找链表中的中间结点
- 2.1 思路概述
- 2.2 代码实现
- 3. 链表的回文结构
- 3.1 思路分析
- 3.2 代码实现
- 总结
✨✨✨学习的道路很枯燥,希望我们能并肩走下来!
本文通过寻找链表中的中间节点,链表的回文序列,链表中倒数第k个节点OJ题问题,来进一步提高双指针在题中的使用,更好的扩展思路,锻炼思维;
1. 寻找链表中倒数第K个节点
题目描述
输入一个链表,输出该链表中倒数第k个结点。
输入:
1,{1,2,3,4,5}
返回值:
{5}
1.1. 思路分析
利用双指针:寻找倒数第k个节点,倒数第k个节点就会距离尾节点是k-1个单位,(尾节点的next==null),k-1这段距离是不变的 ;
可以通过 平移思想,让快指针fast先走k-1个单位,慢指针slow就会距离fast k-1个单位;
保持两节点距离不变再平移两节点(同时移动一步或几步),当快的指针指向尾节点时,slow指针对应的就是倒数第k个节点;
1.2 代码实现
代码实现具体操作:
① 可以定义两个指针fast,slow并初始化为第一个节点位置
② 让fast指针先走k-1步,这样fast与slow指针就相距k-1个位置;
③ 再让两指针一起一步一步走;(两指针之间距离保持相对静止)
④ 当fast.next == null 时,走到尾节点,此时slow所对应的位置就是倒数第K个位置;
代码实现
public ListNode FindKthToTail(ListNode head,int k) {
//k小于0或者没有节点
if(k <= 0 || head == null) {
return null;
}
ListNode fast = head;
ListNode slow = head;
//让fast先走k-1步
while(k-1 != 0) {
fast = fast.next;
//fast不合法,超出节点个数:例如一共4个节点,要求寻找倒数第6个的位置 - err
if(fast == null) {
return null;
}
k--;
}
//两指针一起一步一步走;
while(fast.next != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
2. 寻找链表中的中间结点
题目描述:
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
题目分析
对于奇数结点,返回中间结点即可;对于偶数结点,返回中间两个的第二个结点
2.1 思路概述
使用快慢双指针,让快指针每次走两步,慢指针每次走一步,当快指针为null时,慢指针指向的就是中间结点位置;
为什么让快指针一次走两步呢?
快指针一次走两步,慢指针一次走一步,他们的相对位移是一步,中间不会有跳过;如果快指针一次走三步,他们中间的相对位移就是二,会有遗漏的;对于上述例子第二个,如果快指针一次走三步,返回的结点是3而不是4了所以会有遗漏;
2.2 代码实现
【注】代码考注意事项
① 考虑特殊情况,没有结点或者只有一个结点
② 定义双指针fast,slow
③ 快指针结束标志:fast == null (偶数个结点) || fast.next == null (奇数个结点)
④ 返回slow
public ListNode middleNode(ListNode head) {
//快慢指针:快的走两步,慢的走一步
//没有结点
if(head == null) {
return null;
}
//只有一共结点
if(head.next == null) {
return head;
}
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null) {//当找到slow位置时,fast结束条件
fast = fast.next.next; //走两步
slow = slow.next;
}
return slow;
}
3. 链表的回文结构
题目描述:
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
测试样例:
1->2->2->1
返回:true
3.1 思路分析
根据题目,可知对于回文就是从左往右,和从右往左多是一样;
可以定义快慢指针先找到中间结点,从中间结点开始翻转中间结点之后的结点,这样从两头开始向中间比较值,如果都一样,就是回文序列;
奇数图示:
偶数图示:
3.2 代码实现
① 定义双指针fast,slow
② 寻找中间结点 (上述例题中有,不理解可以往前翻)
快指针走两步,慢指针走一步
③ 记录翻转结点的位置 cur
④ 翻转结点:翻转cur结点之前,需要记录cur后一个结点的位置,如果之间翻转,就会找不到之前的位置而出错( 翻转结点之前一定要记录后一个结点curNext )
⑤ 比较翻转完后前后结点的值: 两个指针都向中间结点靠近,循环结束条件结束head != slow
【注】 (可参考上述图例)
对于偶数个结点情况:head.next == slow;偶数情况如果不这样使用,会发生空指针异常而出错;
对于奇数个结点情况是:head != slow
public boolean chkPalindrome(ListNode A) {
// write code here
//寻找中间节点
ListNode fast = A;
ListNode slow = A;
while(fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
//slow跳出来就是之间结点位置
//记录翻转节点起始位置
ListNode cur = slow.next;
while(cur != null) {
ListNode curNext = cur.next;//记录cur后面结点的位置
cur.next = slow;// 结点翻转
//slow,cur后移动准备下一次翻转
slow = cur;
cur = curNext;
}
//翻转完节点后,slow位于末端
//比较前后节点的值
while(A != slow) {
if(A.val != slow.val) {
return false;
}
//对于偶数情况:A.next == slow
//对于奇数情况是:A != slow
if(A.next == slow) {//偶数情况
return true;
}
//A,slow向中间移动
A = A.next;
slow = slow.next;
}
//跳出循环,说明链表前后值相等
return true;
}
总结
✨✨✨各位读友,本篇分享到内容如果对你有帮助给个👍赞鼓励一下吧!!
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!