目录
✿LeetCode24.两两交换链表中的节点❀
✿LeetCode19.删除链表的倒数第N个节点❀
✿LeetCode面试题 02.07. 链表相交❀
✿LeetCode142.环形链表||❀
✿LeetCode24.两两交换链表中的节点❀
链接:24.两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
我发现我已经找到写链表题的秘诀了,就是画图模拟,这样真的可以让你的思路很清晰,如果直接看代码的话,可能一下就绕进去了,但是画图你可以自己操作指针指向哪,直到完成题目的要求,以下是我写的代码:
public ListNode swapPairs(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){
ListNode temp1=cur.next;
ListNode temp2=cur.next.next.next;
cur.next=cur.next.next;
temp1.next.next=temp1;
temp1.next=temp2;
cur=temp1;
}
return dummy.next;
}
此外还可以用递归,递归更像是直白的思路
public ListNode swapPairs(ListNode head) {
// 递归版本
if(head==null || head.next==null){
return head;
}
ListNode next=head.next;
ListNode newNode=swapPairs(next.next);
next.next=head;
head.next=newNode;
return next;
}
测试用例:
1.输入偶数节点个数的链表
2.输入奇数节点个数的链表
3.输入只有一个节点的链表
4.输入空链表
✿LeetCode19.删除链表的倒数第N个节点❀
链接:19.删除链表的倒数第N个节点
给你一个链表,删除链表的倒数第
n
个结点,并且返回链表的头结点。
对于链表题目,不得不考虑头结点,如果要删除的元素是头结点该怎么操作呢?答案就是设计一个虚拟头结点dummy,这样头结点就可以看成一个普通的节点进行操作了,这道题的思路就是让fast先走n+1步,然后fast和slow一起走,fast=null的时候,slow正好是要删除节点的前一个节点,具体代码如下:
public ListNode removeNthFromEnd(ListNode head, int n) {
// 1 <= n <= sz
// 1 <= sz <= 30
ListNode dummy=new ListNode(0);
dummy.next=head;
ListNode fast=dummy;
// fast先走n+1步
for(int i=0;i<n+1;i++){
fast=fast.next;
}
ListNode slow=dummy;
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next;
return dummy.next;
}
测试用例:
1.删除链表中间的一个节点
2.删除链表末尾的一个节点
3.删除头结点
4.n<1或n>size(题目没有这类用例)
5.链表为空(题目没有这类用例)
✿LeetCode面试题 02.07. 链表相交❀
链接:02.07.链表相交
给你两个单链表的头节点
headA
和headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回null
。题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
快慢指针可以解决链表中的很多问题,此题就是一个典型的例子,先计算出两个链表的长度差len,长的链表先走 len步,然后两个链表一起走,相等的时候即相交,代码如下:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null || headB==null){
return null;
}
int lenA=0;
int lenB=0;
ListNode indexA=headA;
ListNode indexB=headB;
while(indexA!=null){
lenA++;
indexA=indexA.next;
}
while(indexB!=null){
lenB++;
indexB=indexB.next;
}
if(lenB>lenA){
ListNode temp=headA;
headA=headB;
headB=temp;
}
indexA=headA;
indexB=headB;
int len=Math.abs(lenA-lenB);
while(len>0){
indexA=indexA.next;
len--;
}
while(indexA!=null && indexB!=null){
if(indexA==indexB){
return indexA;
}
indexA=indexA.next;
indexB=indexB.next;
}
return null;
}
测试用例:
- 输入两个相交的链表且两个链表的长度不同
- 输入两个不想交的链表
- 输入的两个链表其中有一个是空链表
- 输入的两个都是空链表
- 输入两个相等的链表(从头结点就相交)
- 输入的两个链表最后一个节点才相交
✿LeetCode142.环形链表||❀
链接:142.环形链表||
给定一个链表的头节点
head
,返回链表开始入环的第一个节点。 如果链表无环,则返回null
。如果链表中有某个节点,可以通过连续跟踪
next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果pos
是-1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表
这道题首先要判断是否有环,定义一个快慢指针,快指针每次走两步,慢指针每次走一步,如果两个指针相遇的话就代表有环,如果快指针指向null了就代表无环(环形链表拥有不可能指向空),如果有环再计算入环的第一个节点的下标,计算过程如下:
快指针走了x+y+n(y+z),慢指针走了x+y,又有快指针走的步数是慢指针的两倍,所以
x+y+n(y+z)=2(x+y) -> x+y=n(y+z)
我们要求的是x: x=n(y+z)-y=(n-1)(y+z)-z
当n=1的时候 x=z
所以当快慢指针相遇时,一个指针从相遇点出发,一个指针从头结点出发,两指针相遇的节点即为入环的第一个节点,代码如下:
public ListNode detectCycle(ListNode head) {
if(head==null || head.next==null){
return null;
}
ListNode fast=head;
ListNode slow=head;
// 看是否有环
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
// 有环
if(fast==slow){
slow=head;
while(fast!=null){
if(slow==fast){
return slow;
}
slow=slow.next;
fast=fast.next;
}
}
}
return null;
}
测试用例:
- 输入一个有环的链表
- 输入一个无环的链表
- 输入一个只有一个节点的链表
- 输入一个空链表