24. 两两交换链表中的节点
1.题目:
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
https://leetcode.cn/problems/swap-nodes-in-pairs
2.思想:
递归和指针两种
3.代码:
public ListNode swapPairs(ListNode head) {
//指针
ListNode s=new ListNode(-1);
s.next=head;
ListNode temp;
ListNode curr=s;
ListNode one;
ListNode two;
while(curr.next!=null &&curr.next.next!=null){
temp=curr.next.next.next;
one=curr.next;
two=curr.next.next;
curr.next=two;
two.next=one;
one.next=temp;
curr=one;
}
return s.next;
}
class Solution {
//递归
public ListNode swapPairs(ListNode head) {
if(head==null ||head.next==null){
return head;
}
ListNode two=head.next;
ListNode newnode=swapPairs(two.next);
two.next=head;
head.next=newnode;
return two;
}
}
4.总结:
19.删除链表的倒数第N个节点
1.题目:
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
https://leetcode.cn/problems/remove-nth-node-from-end-of-list
2.思想:
指针和递归
指针:
双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾null。删掉slow所指向的节点就可以了。
3.代码:
//快慢指针
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode s=new ListNode(-1,head);
ListNode fastp1=s;
ListNode slowp2=s;
for(int i=0;i<n+1;i++){
fastp1=fastp1.next;
}
while(fastp1!=null){
slowp2=slowp2.next;
fastp1=fastp1.next;
}
slowp2.next=slowp2.next.next;
return s.next;
}
}
//递归
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode s=new ListNode(-1,head);
recursion(s,n);
return s.next;
}
private int recursion(ListNode p,int n){
if(p==null){
return 0;
}
int nth=recursion(p.next,n);//下一个节点在倒数第几个位置
if(nth==n){
p.next=p.next.next;
}
return nth+1; //当前p节点的位置
}
}
4.总结:
160.面试题 02.07. 链表相交
1.题目:
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
https://leetcode.cn/problems/intersection-of-two-linked-lists
2.思想:普通移动和HashSet
3.代码:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
int lenA = 0, lenB = 0;
while (curA != null) { // 求链表A的长度
lenA++;
curA = curA.next;
}
while (curB != null) { // 求链表B的长度
lenB++;
curB = curB.next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
//1. swap (lenA, lenB);
int tmpLen = lenA;
lenA = lenB;
lenB = tmpLen;
//2. swap (curA, curB);
ListNode tmpNode = curA;
curA = curB;
curB = tmpNode;
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上(末尾位置对齐)
while (gap-- > 0) {
curA = curA.next;
}
// 遍历curA 和 curB,遇到相同则直接返回
while (curA != null) {
if (curA == curB) {
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
}
//HashSet
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> map=new HashSet<ListNode>();
ListNode temp=headA;
while(temp!=null){
map.add(temp);
temp=temp.next;
}
temp=headB;
while(temp!=null){
if(map.contains(temp)){
return temp;
}
temp=temp.next;
}
return null;
}
}
4.总结:
142.环形链表II
1.题目:
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
https://leetcode.cn/problems/linked-list-cycle-ii
2.思想:
判断链表是否有环:可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
如何找到环:从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。
3.代码:
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(slow==fast){
slow=head;
while(slow!=fast){
slow=slow.next;
fast=fast.next;
}
return slow;
}
}
return null;
}
}
4.总结: