①、两两交换链表中的结点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
力扣(LeetCode)链接:https://leetcode.cn/problems/swap-nodes-in-pairs/
事例:
输入:head = [1,2,3,4] 输出:[2,1,4,3]
分析:
这道题需要我们相邻两个结点做交换,然后依次迭代。就以上图为例,我们首先交换结点1和2,变为2-1-3-4,然后交换三四结点得到结果2-1-4-3。在交换34前,我们只需要站在结点1上操作下一个结点和下下个结点,故此题借助一个带有头结点的链表来操作更方便(可以在头结点的位置上处理第一次交换),然后跳转到交换后靠后面的结点进行下一次交换。
代码:
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null) return head;
//使用带有头结点的链表组织
ListNode res = new ListNode();
res.next = head;
ListNode tmp = res; //遍历整个链表
ListNode firstNode;
ListNode secondNode;
ListNode secondNext;
while(tmp.next != null && tmp.next.next != null){
firstNode = tmp.next; //第一个结点
secondNode = tmp.next.next; //第二个结点
secondNext = tmp.next.next.next; //第二个结点的next结点
//组织一下上面三个结点的关系
secondNode.next = firstNode;
firstNode.next = secondNext;
tmp.next = secondNode;
tmp = firstNode;
}
return res.next;
}
/* firstnode是指要交换的第一个结点
secondnode是指要交换的第二个结点
用secondNext保存第二个结点的后续结点
交换的条件为后续是否有两个结点。(tmp.next != null && tmp.next.next != null)
*/
②、删除链表中倒数第n个结点
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
力扣(LeetCode)链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
事例:
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
思路:
①、使用快慢指针,由于要删除第n个结点,故快指针需要比慢指针先走n步,当快指针到达最后一个结点时,慢指针则到达要删除结点的前一个结点,此时使用slow.next = slow.next.next删除即可。
②、借助栈实现,由于栈是先入后出,故将链表所有结点弹入,然后弹出n次就可以获得要删除的结点,此时如果栈为空,则表明要删除第一个结点,head = head.next。反之,则直接peek()获得删除结点的前一个结点进行删除。
代码:
public ListNode removeNthFromEnd(ListNode head, int n) {
// if(head == null || head.next == null){
// return null;
// }
// ListNode help = new ListNode();
// help.next = head;
// //定义快慢指针
// ListNode fast = help;
// ListNode slow = help;
// for(int i = 0;i < n;i++){
// fast = fast.next;
// }
// while(fast.next != null){
// fast = fast.next;
// slow = slow.next;
// }
// slow.next = slow.next.next;
// return help.next;
//栈实现
Stack<ListNode> stack = new Stack<>();
ListNode cur = head;
while(cur != null){
stack.push(cur);
cur = cur.next;
}
for(int i = 0;i < n;i++){
//弹到要删除的结点
cur = stack.pop();
}
if(stack.isEmpty()){
//删除第一个结点
head = head.next;
}else{
ListNode tmp = stack.peek();
tmp.next = tmp.next.next;
}
return head;
}
③、链表相交
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
力扣(LeetCode)链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci
思路:
①、分别统计两个链表的长度,获取差值n,然后将长的链表走n步,确保两链表一样长,此时位与同一起跑线,然后再一起遍历链表,如果值相等,则说明有相交点 返回,如果循环结束,则没有相交,返回null
②、借助HashSet判断,hashSet中有一个contains方法判断是否有该结点。在一个循环中遍历链表A,将链表A所有的结点存入set中,然后再遍历链表B,若要存入重复结点,则返回结点,若没有,则返回null。
代码:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// if(headA == null || headB == null){
// return null;
// }
// int n = 0; //记录两链表的长度差
// ListNode p1 = headA;
// ListNode p2 = headB;
// while(p1 != null){
// n++;
// p1 = p1.next;
// }
// while(p2 != null){
// n--;
// p2 = p2.next;
// }
// p1 = headA;
// p2 = headB;
// if(n > 0){ //证明headA比headB长
// for(int i = 0;i < n;i++){
// p1 = p1.next;
// }
// }else{
// int sub = Math.abs(n);
// for(int i = 0;i < sub;i++){
// p2 = p2.next;
// }
// }
// while(p1 != null){
// if(p1 == p2){
// break;
// }
// p1 = p1.next;
// p2 = p2.next;
// }
// return p1;
//借助hashSet实现
HashSet<ListNode> set = new HashSet<>();
ListNode p1 = headA;
ListNode p2 = headB;
while(p1 != null){
set.add(p1);
p1 = p1.next;
}
while(p2 != null){
if(set.contains(p2)){
return p2;
}
p2 = p2.next;
}
return null;
}
④、环形链表 Ⅱ
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
力扣(LeetCode)链接:https://leetcode.cn/problems/linked-list-cycle-ii
事例:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。
思路:
①、使用快慢指针,快指针每次走两步,慢指针每次走一步,若有环,则快指针走不到null,快慢指针会相遇,若快指针的下一步成null,则无环 返回null (因为快指针每次都走两步,不能直接判断快指针是否为null 会触发空指针异常)。快慢指针相遇后,将快指针指向头结点,然后速度变的跟慢指针一样,当它两再次相遇时,则相遇点为环。
②、借助HashSet求环,遍历整条链表,若出现重复结点,则说明有环,走到null 则说明无环,使用contains方法判断。
代码:
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){
break;
}
}
if(fast == null || fast.next == null){
//说明无环
return null;
}
fast = head;
while(slow != fast){
fast = fast.next;
slow = slow.next;
}
return fast;
//借助HashSet寻找
// HashSet<ListNode> set = new HashSet<>();
// ListNode p1 = head;
// while(p1 != null){
// if(set.contains(p1)){
// return p1;
// }else{
// set.add(p1);
// }
// p1 = p1.next;
// }
// return null;
}