写在前面:这几个题确实好题,双指针大法好(快指针慢指针),值得反复思考。
1 24. 两两交换链表中的节点
题目: 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
提示:
- 链表中节点的数目在范围
[0, 100]
内 0 <= Node.val <= 100
思路: 首先结点顺序交换,考虑用双指针记录交换结点和后续结点起始位置。其次返回链表表头,考虑使用虚拟头结点。
注意:双结点使用时一个记录当前交换对的第一个结点,另一个记录下组交换对结点的位置。
Java实现
/**
* 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) {
// 设置虚拟头结点
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode cur = dummyHead;
ListNode temp,temp1;
while(cur.next!=null && cur.next.next!= null){ // 保证至少有两个节点用来交换
temp = cur.next; // 保存两个节点中的第一个节点
temp1 =cur.next.next.next; // 保存交换位置后的起始位置的新节点
cur.next = temp.next;
cur.next.next = temp;
cur.next.next.next = temp1;
cur = cur.next.next;
}
return dummyHead.next;
}
}
2 19. 删除链表的倒数第 N 个结点
题目: 给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
提示:
- 链表中结点的数目为
sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
思路:删除倒数第n个结点,最直接的方法是遍历表长后再确定删除结点位置。还可以采用双指针法,一个指针定位链表尾部,另一个指针定位删除结点前一位,两个指针间隔n。
注意:链表尾部指针先走n位,然后定位指针和链表指针同步行进。
Java实现
/**
* 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 dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode sign = dummyHead; // 被删除节点前一位
ListNode temp = dummyHead; // 查找链表结尾
// 删除倒数第n个节点,向前预留n+1位节点
for(int i =0;i<=n;i++){
temp = temp.next;
}
// temp只判断当前指向状态
while(temp!= null){
temp = temp.next;
sign = sign.next;
}
sign.next = sign.next.next;
return dummyHead.next;
}
}
3 面试题 02.07. 链表相交
题目: 给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。图示两个链表在节点 c1
开始相交:
题目数据 保证 整个链式结构中不存在环。注意,函数返回结果后,链表必须 保持其原始结构 。
提示:
listA
中节点数目为m
listB
中节点数目为n
0 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
- 如果
listA
和listB
没有交点,intersectVal
为0
- 如果
listA
和listB
有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]
思路:两个链表可以相交,相交结点一致,相交部分长度一致,因此链表长度不同时一定是以短链表长度为比较起点。然后,逐个比较结点是否一致即可。
注意:相交部分是同一结点,因此地址是一致的,比较时注意不要单纯以结点值为评判标准。
Java实现
/**
* 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) {
// 分别遍历链表得到链表长度
int la=0,lb=0;
ListNode dummyHeadA = headA;
ListNode dummyHeadB = headB;
while(dummyHeadA!= null){
la++;
dummyHeadA = dummyHeadA.next;
}
while(dummyHeadB!=null){
lb++;
dummyHeadB = dummyHeadB.next;
}
// 表头复原
dummyHeadA = headA;
dummyHeadB = headB;
// 根据la、lb长度分情况判断,为简化计算可将A设置为长链,B为短链
if(la<lb){
int t =lb;
lb = la;
la = t;
ListNode temp = dummyHeadA;
dummyHeadA = dummyHeadB;
dummyHeadB = temp;
}
for(int i=0;i<la-lb;i++){
dummyHeadA = dummyHeadA.next;
}
while(dummyHeadA!=null){
if(dummyHeadA == dummyHeadB){
return dummyHeadA;
}
dummyHeadA = dummyHeadA.next;
dummyHeadB = dummyHeadB.next;
}
return null;
}
}
4 142. 环形链表 II
题目:给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。
提示:
- 链表中节点的数目范围在范围
[0, 104]
内 -105 <= Node.val <= 105
pos
的值为-1
或者链表中的一个有效索引
思路:首先,确定是否有环;其次,确定入口位置。确实难,目前还描述不清楚,推荐直接看解析 环形链表。
注意:确定环入口的数学问题要想清楚。
Java实现
/**
* 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) {
ListNode fast = head;
ListNode slow = head;
// 判断是否有环
while(fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if (fast==slow){ //判断有环
ListNode index1 = fast;
ListNode index2 = head;
while(index1!=index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}