文章目录
24. 两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
- 输入:head = [1,2,3,4]
- 输出:[2,1,4,3]
示例 2:
- 输入:head = []
- 输出:[]
示例 3:
- 输入:head = [1]
- 输出:[1]
解题思路
正常模拟就可以,最好用虚拟头结点,就不用在循环外单独考虑处理头结点了。画图研究步骤不容易把自己绕晕,还是要多动笔
源码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode pre = head;
ListNode cul = head.next;
ListNode temp =head;
ListNode empty = new ListNode(-1, head);
head=head.next;
while(cul.next !=null){
temp=cul.next;
empty.next = cul;
cul.next = pre;
pre.next = temp;
empty=pre;
pre=temp;
if(pre.next==null){
return head;
}
cul=pre.next;
}
empty.next=cul;
cul.next=pre;
pre.next=null;
return head;
}
}
19.删除链表的倒数第N个节点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例 1:
- 输入:head = [1,2,3,4,5], n = 2
- 输出:[1,2,3,5]
示例 2:
- 输入:head = [1], n = 1
- 输出:[]
示例 3:
- 输入:head = [1,2], n = 1
- 输出:[1]
解题思路
典型的双指针题目,让fast先移动n,然后slow与fast同步移动,直到fast移动到循环末尾然后删除此时slow指向的元素即可
源码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode empty = new ListNode(-1, head);
ListNode fast = empty;
ListNode slow = empty;
if(head.next == null){
return null;
}
for(int i=0; i<n; i++){
fast=fast.next;
}
while(fast.next!=null){
slow=slow.next;
fast=fast.next;
}
if(slow.next.next==null){
slow.next=null;
}
else{
slow.next=slow.next.next;
}
// return head; 这里假如删的是头结点,直接这样输出会报错
return empty.next;
}
}
面试题 02.07. 链表相交
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入:headA = [4,1,8,4,5], headB = [5,0,1,8,4,5]
输出:Intersected at ‘8’
解题思路
先循环求出两个链表的长度,再把较长的链表指针向后移与较短的对齐,依次判断是否相交,就能实现O(n)级的时间复杂度
源码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null||headB==null){
return null;
}
ListNode emptyA = new ListNode(-1, headA);
ListNode emptyB = new ListNode(-2, headB);
ListNode a = headA;
ListNode b = headB;
int lenA=0, lenB = 0;
ListNode temp = headA;
while(temp!=null){
temp=temp.next;
lenA++;
}
temp=headB;
while(temp!=null){
temp=temp.next;
lenB++;
}
if(lenA>lenB){
for(int i = 0; i<lenA-lenB; i++){
a=a.next;
}
}
else if(lenA<lenB){
for(int i = 0; i<lenB-lenA; i++){
b=b.next;
}
}
while(a!=null){
if(a == b){
return a;
}
a = a.next;
b = b.next;
}
return null;
}
}
142.环形链表II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4]
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
解题思路
可以分成两步来做:
1.判断是否有环
可以用快慢指针法,slow一次走一个节点,fast一次走两个节点,只要能slow和fast能相遇,那就必定存在环
2.判断哪个节点是环的入口
由上图可得,相遇时:slow=x+y,fast = x+y+n(y+z)
∵ fast=slow*2
∴ 2(x+y)=x+y+n(y+z)
∴x+y=n(y+z)
∴x=(n-1)(y+z)+z
∴当n=1时,可化简为x=z
即,当快慢指针相遇时,定义a指向头结点,b指向相遇节点,两个指针同步增加,相遇时的节点即为环的入口
当n>1时情况不变,b在多转n-1圈后在入口节点遇到a
详细思路可见代码随想录
源码
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null || head.next ==null){
return null;
}
ListNode slow = head;
ListNode fast = head;
ListNode index = head;
ListNode index2 = head;
while(fast.next != null && fast.next.next!=null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast){
index = fast;
while(index != index2){
index = index.next;
index2 = index2.next;
}
return index;
}
}
return null;
}
}
总结
今天题目大体上思路都明白,有好几个细节调了好久,什么与或、等不等于之类的,基础还是不太牢,能自己debug出来还是很有成就感的,对双指针的理解又加深了不少。加油!