目录
12.单链表的排序(中等)(二分/归并排序+递归+快慢指针)
[13. 判断一个链表是否为回文结构(简单)(快慢指针+反转链表)](#13. 判断一个链表是否为回文结构(简单)(快慢指针+反转链表))
8.链表中倒数最后k个结点(简单)(快慢指针)
题目:

思路:
流程演示:(来自于题解链表中倒数最后k个结点_牛客题霸_牛客网 (nowcoder.com))

代码:
java
public class Solution {
public ListNode FindKthToTail (ListNode pHead, int k) {
ListNode fast = pHead;
ListNode slow = pHead;
//快指针先走k步
for(int i=0;i<k;i++){
if(fast==null){
return null;
}
fast=fast.next;
}
//双指针同时开始走
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
return slow;
}
}
9.删除链表的倒数第n个节点(中等)(快慢指针)
题目:

思路:
跟上一题差不多,区别就在于上面是找到对应的节点,这里是找到后要删除该节点,所以slow不能直接定位到该节点,而是定位到该节点的前一个节点,然后使用slow.next = slow.next.next进行删除,
同时要先写一个哑节点,指向head,fast和slow要从哑节点开始遍历(能完美解决删除头结点的情况),所以,fast要遍历n+1次,slow才开始走,跟上一题比,fast跟slow相差n+1个节点,(可以自己模拟一下就清晰了)
代码:
java
public class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if (head == null || n <= 0) {
return head;
}
// 使用哑节点(dummy node)简化边界情况处理
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode fast = dummy;
ListNode slow = dummy;
// 快指针先走 n+1 步
for (int i = 0; i <= n; i++) {
// 如果 n 大于链表长度,返回原链表
if (fast == null) {
return head;
}
fast = fast.next;
}
// 双指针同时移动,直到快指针到达末尾
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
// 删除目标节点
if (slow.next != null) {
slow.next = slow.next.next;
}
return dummy.next;
}
}
10.两个链表的第一个公共结点(简单)(双指针)
题目:


(上面的示例写得不太清楚,反之只要知道,传入两个链表,找出他们的公共节点,没有则返回null)
思路:
依旧使用双指针,对于第一个链表,从头结点走到尾节点,一共是x1+y的距离,对于第二个链表则是x2+y的距离,如果我们给他们分别加上x2和x1,那么他们的距离就相等了,即x1+y+x2=x2+y+x1,也就是说,当两条链表分别走到尾时,不会停下,而是直接跳转到对面的链表继续遍历,这样操作最后一定会在公共点相遇,问题就解决了

代码:
java
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode p1 = pHead1;
ListNode p2 = pHead2;
while(p1!=p2){
p1=((p1==null)?pHead2:p1.next);
p2=((p2==null)?pHead1:p2.next);
}
return p1;
}
}
11.链表相加(二)(中等)(反转链表)
题目:


思路:
这题如果直接对其两个链表的尾节点开始相加的话会很麻烦,所以主要思路在于反转链表再相加,
第一次反转:先将原始的连个链表都反转了(反转方法看第一期),这样就方便对其上下链表的位数了,然后定义一个哑节点dummy用来永远指向答案链表头节点,定义一个pre用来辅助衔接答案到答案链表上,定义一个tmp用来存储相加的进位数
关键循环:每次循环都将两个链表的val值存进val中,然后使用val/10求出进位数tmp,然后使用val%10求出进位后的val,当作答案节点接入答案链表中。如果循环结束了但是还有进位tmp,则还要进行一次pre.next=new ListNode(tmp)操作
第二次循环:将求出的答案链表dummy.next反转即可得到答案
代码:
java
public class Solution {
public ListNode addInList (ListNode head1, ListNode head2) {
head1=ReverseList(head1);
head2=ReverseList(head2);
ListNode dummy= new ListNode(0); //哑节点,用来指向头结点
ListNode pre = dummy; //中间节点,用来连接下一个要接入的节点
int tmp=0; //存储进位数
while(head1!=null||head2!=null){
int val=tmp; //赋值进位数给val
if(head1!=null){
val+=head1.val;
head1=head1.next;
}
if(head2!=null){
val+=head2.val;
head2=head2.next;
}
tmp=val/10; //求出进位数tmp
pre.next=new ListNode(val%10); //求出进位后的val
pre=pre.next;
}
if(tmp>0){
pre.next=new ListNode(tmp);
}
return ReverseList(dummy.next); //将求出的链表反转即可得到答案
}
public ListNode ReverseList (ListNode head) {
ListNode pre=null;
ListNode next=null;
while(head!=null){
next=head.next;
head.next=pre;
pre=head;
head=next;
}
return pre;
}
}
12.单链表的排序(中等)(二分/归并排序+递归+快慢指针)
题目:

思路:
这题的主要思路就是二分+递归 ,跟上一篇的"链表中的节点每k个一组翻转 "类似,先使用一个快慢指针找出当前链表的中间节点(注意起始位置和边界),然后将当前链表分成两部分分别递归,最后使用经典的哑节点dummy和辅助节点pre进行排序/合并左右链表,注意最后要判断是否合并完pre.next=((l!=null)?l:r),然后依次返回dummy.next即可
流程演示:(来自于题解单链表的排序_牛客题霸_牛客网 (nowcoder.com))

时间复杂度O(NlogN):N表示链表结点数量,二分归并算法O(NlogN)
空间复杂度O(1):仅使用常数级变量空间
代码:
java
public class Solution {
public ListNode sortInList (ListNode head) {
//预处理/递归结束条件
if (head == null || head.next == null) {
return head;
}
//快慢指针找出中间节点
ListNode fast=head.next;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
}
//递归操作
ListNode tmp=slow.next;//右半部分的头结点
slow.next=null;//左半部分的边界
ListNode l=sortInList(head);
ListNode r=sortInList(tmp);
//排序合并两个链表
ListNode dummy=new ListNode(0);
ListNode pre=dummy;
while(l!=null&&r!=null){
if(l.val<r.val){
pre.next=l;
l=l.next;
}else{
pre.next=r;
r=r.next;
}
pre=pre.next;
}
pre.next=((l!=null)?l:r); //最后添加未对比的链表部分
return dummy.next;
}
}
13. 判断一个链表是否为回文结构(简单)(快慢指针+反转链表)
题目:

思路:
这题的主要思路就是先使用快慢指针 找出中间节点,将链表分为左右两部分,如果是奇数个节点(循环结束后fast!=null)则要将中间节点去除slow=slow.next,然后将后半部分的链表进行反转 ,反转后再与前半部分链表head进行逐一比较即可,循环结束条件是tmp!=null,只考虑后半部分即可,因为前后部分的节点都是一样数量的
流程演示:(来自于题解判断一个链表是否为回文结构_牛客题霸_牛客网 (nowcoder.com))


代码:
java
public class Solution {
public boolean isPail (ListNode head) {
//快慢指针找出中间节点
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
//如果fast不为空,说明链表的长度是奇数个,则跳过中间节点
if(fast!=null){
slow=slow.next;
}
//依次比较两个链表的值是否相等
ListNode tmp=ReverseList(slow);
while(tmp!=null){
if(head.val!=tmp.val){
return false;
}
head=head.next;
tmp=tmp.next;
}
return true;
}
public ListNode ReverseList (ListNode head) {
ListNode pre=null;
ListNode next=null;
while(head!=null){
next=head.next;
head.next=pre;
pre=head;
head=next;
}
return pre;
}
}
14.链表的奇偶重排(中等)(双指针)
题目:

思路:
这题的思路主要是用两个链表分别记录奇数和偶数节点,最后再拼接在一起。因为是偶数在后面,所以使用一个哑节点evenHead来标记,奇数链表则直接用head即可。拆链表的时候先将偶数的下一个节点接入到奇数链表odd后(odd.next=even.next),偶数链表再将奇数节点的下一个接到自己后面(even.next=odd.next),循环条件even!=null是为了处理奇数个节点的链表的终止,even.next!=null是为了处理偶数个节点的链表的终止,最后别忘了将偶数链表的重新接在奇数链表后面(odd.next=evenHead)
流程演示:(来自于题解链表的奇偶重排_牛客题霸_牛客网 (nowcoder.com))


代码:
java
public class Solution {
public ListNode oddEvenList (ListNode head) {
//预处理
if(head==null||head.next==null){
return head;
}
ListNode evenHead=head.next;//永远指向偶数链表的头结点
ListNode odd=head;//记录奇数链表
ListNode even=head.next;//记录偶数链表
while(even!=null&&even.next!=null){
odd.next=even.next;
odd=odd.next;
even.next=odd.next;
even=even.next;
}
odd.next=evenHead;//将偶数链表的重新接在奇数链表后面
return head;
}
}
15.删除有序链表中重复的元素-I(简单)(模拟+遍历)
题目:

思路:
这题很简单,使用一个辅助节点cur=head,一直遍历链表即可,如果当前节点的值跟下一个节点的值相等,就跳过cur.next=cur.next.next,否则正常遍历cur=cur.next
代码:
java
public class Solution {
public ListNode deleteDuplicates (ListNode head) {
//预处理
if(head==null||head.next==null){
return head;
}
ListNode cur=head;
while(cur!=null&&cur.next!=null){
if(cur.val==cur.next.val){
cur.next=cur.next.next;
}else{
cur=cur.next;
}
}
return head;
}
}
16.删除有序链表中重复的元素-II(中等)(模拟+遍历)
题目:

思路:
这题跟上一题的主要区别就是将出现两个及以上的数字全都删掉,而不是留下1个,因此辅助节点cur应该在每个要衔接的节点的前一个节点,方便全部跳过重复的,同时要有一个哑节点dummy,防止头结点出现重复的情况,方便删除头结点,最后就是核心的循环遍历链表了,遇到重复的值直接跳过即可,细节上看代码即可,思路跟上一题差不多
流程演示:(来自题解删除有序链表中重复的元素-II_牛客题霸_牛客网 (nowcoder.com))

代码:
java
public class Solution {
public ListNode deleteDuplicates (ListNode head) {
//预处理
if(head==null||head.next==null){
return head;
}
ListNode dummy=new ListNode(0);//哑节点
dummy.next=head;
ListNode cur=dummy;//辅助节点
while(cur.next!=null&&cur.next.next!=null){
if(cur.next.val==cur.next.next.val){
int temp=cur.next.val;
while(cur.next!=null&&cur.next.val==temp){
cur.next=cur.next.next;
}
}else{
cur=cur.next;
}
}
return dummy.next;
}
}
本篇文章到此结束,如果对你有帮助可以点个赞吗~
个人主页有很多个人总结的 Java、MySQL 等相关的知识,欢迎关注~