前言
今天是4道链表题目,都是经典题目。 两两交换链表中的节点 删除链表的倒数第 N 个结点 面试题 02.07. 链表相交 142. 环形链表 II
两两交换链表中点节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
首先分析一下交换过程,假如有一个链表1,2,3,4。我们首先设置一个虚拟头节点0,然后让节点从0指向2,2指向1,1指向3,大概就是这么的一个过程。
这里要注意结束条件,要记得先cur.next!=null否则先判断cur.next.next!=null会报错,因为null节点没有next节点。
下面是具体代码实现:
class Solution {
public ListNode swapPairs(ListNode head) {
//使用虚拟头节点进行两两交换,两个节点交换一次
ListNode headnode=new ListNode(-1);
headnode.next=head;
ListNode cur=headnode;
ListNode firstNode;
ListNode secondeNode;
ListNode temp;//保存第三个节点
while(cur.next!=null&&cur.next.next!=null){//如果是偶数节点是cur.next=null,奇数节点cur.next.next=null
//记录cur的下一个节点
temp=cur.next.next.next;//第三个节点的位置
//节点之前两两交换。
firstNode=cur.next;
secondeNode=cur.next.next;
//cur节点是0,firstnode节点是secondNode节点是2
//需要0-2-1-3
cur.next=secondeNode;//0到2
secondeNode.next=firstNode;//2到1
firstNode.next=temp;//1到3
cur=firstNode;//将cur向前移动两个位置
}
return headnode.next;
}
}
时间复杂度O(N),空间复杂度O(1)。
删除链表倒数第n个节点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
lic ListNode removeNthFromEnd(ListNode head, int n) {
//删除链表的倒数第n个节点
//两次扫描挺好想的,现在困难的是一次扫描
//我的思路,双指针,第一个指针和第二个指针相差n个就可以了,这样就实现了一次循环找到倒数第n个节点
ListNode fast=head,slow=head;
for(int i=0;i<n;i++){
fast=fast.next;
}
if(fast==null){
return head.next;
}
//这样快指针比慢指针快了n个,快指针到头位置的时候慢指针就是倒数第n个指针
while(fast.next!=null){
slow=slow.next;
fast=fast.next;
}
//现在到了第n个的位置,需要删除第n个位置指针
if(slow.next!=null){
slow.next=slow.next.next;
}
return head;
双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。
链表相交
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
链表相等的含义是两个节点相同,而不是只是值相同。我们先求链表长度,然后如果cura的长度小,将cura和curb的长度进行交换,让a节点和b节点名称进行交换,确保cura的长度更长。
然后将cura的指针移动到相关的curb长度相同的节点,然后两两节点比较,如果相同就返回,如果不相同互相移动下一个节点。
我的代码实现:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//先求长度,
ListNode cura=headA;
ListNode curb=headB;
int alength=0;
int blegnth=0;
while(cura!=null){
alength++;
cura=cura.next;
}
while(curb!=null){
blegnth=blegnth+1;
curb=curb.next;
}
cura=headA;
curb=headB;
if(alength<blegnth){
//如果a的长度小于b的长度
//交换长度和交换节点
int tmp_len;
tmp_len=alength;
alength=blegnth;
blegnth=tmp_len;
//交换相关节点
ListNode tmpNode=new ListNode(-1);
tmpNode=cura;
cura=curb;
curb=tmpNode;
}
//
int len_result=alength-blegnth;
//过长的链表的进行遍历等相同长度
while(len_result-->0){
cura=cura.next;
}
//对比节点是否是同一个节点
while(cura!=null){
if(cura==curb){
return cura;
}
cura=cura.next;
curb=curb.next;
}
return null;
}
环形链表
题意: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
if(fast==slow){//如果相交证明有环
ListNode index=head;
ListNode index2=fast;//交汇点和head不断走下去一定会交汇
while(index!=index2){
index = index.next;
index2 = index2.next;
}
return index;
}
}
return null;
}
}
可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
并且如果链表中有环,设置两个指针,一个是head链表头节点,一个是相交的位置节点,遍历下去一定会相交的。