题目链接:24.两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
解题思路:看到这道题目的第一想法是暴力解法,从头开始每次循环就交换两个元素,直至最后没有元素或者剩下一个元素时结束循环;不过想想处理重复行为递归是个不错的方式,尝试几次后发现确实可行;看完视频想起来也可以用虚拟头节点。
// 递归解法
class Solution1 {
public ListNode swapPairs(ListNode head) {
//当递归完所有元素(head==null)或者剩下一个元素(head.next==null)时
//直接返回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;
}
}
// 虚拟指针解法
class Solution2 {
public ListNode swapPairs(ListNode head) {
//虚拟头节点
ListNode dummyHead = new ListNode();
dummyHead.next = head;
ListNode cur = dummyHead;
while (cur.next != null && cur.next.next != null) {
ListNode node = cur.next.next;
cur.next.next = node.next;
node.next = cur.next;
cur.next = node;
cur = cur.next.next;
}
//返回交换后链表的头节点
return dummyHead.next;
}
}
题目链接:19.删除链表的倒数第N个结点
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
解题思路:看到这道题目的第一想法是设置快慢指针,开始时快慢指针fast
和slow
都指向头节点,然后快指针先走N
步,然后快慢指针同时向后移动,每次都移动一次,直到快指针指向空,此时慢指针指向的就是待删除的元素的前一个元素,然后将待删除元素删除即可。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
// 快慢指针!
ListNode dummyHead = new ListNode();
dummyHead.next = head;
ListNode fast = dummyHead;
ListNode slow = dummyHead;
for (int i = 0; i < n; i++) {
fast = fast.next;
}
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
// 此时slow已经指向待删除元素的前一个元素,芜湖
ListNode delNode = slow.next;
slow.next = slow.next.next;
delNode.next = null;
return dummyHead.next;
}
}
易错点:i应该小于n而不是小于等于n。
题目链接:面试题 02.07. 链表相交
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
解题思路:看题目没思路,迷迷糊糊的,看完视频恍然大悟原来是要指针相等,不用过于关注所求交点的数值。简单来说就是先想办法得到两个长度相等的链表再一起向后移动,如果相等即为所求交点哈哈。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//(1)
ListNode curA = headA;
ListNode curB = headB;
//(2)
// 用来记录A链表的长度
int lengthA = 0;
// 用来记录B链表的长度
int lengthB = 0;
while (curA != null) {
lengthA++;
curA = curA.next;
}
while (curB != null) {
lengthB++;
curB = curB.next;
}
// 让 curA 重新指向 headA
curA = headA;
// 让 curB 重新指向 headB
curB = headB;
if (lengthA < lengthB) {
// 如果A链表长度小于B链表长度 就交换lendthA和lengthB的值 以保证后面长度差 lengthA - lengthB 是正值;
int temp = lengthA;
lengthA = lengthB;
lengthB = temp;
// 如果A链表长度小于B链表长度 就交换 curA 和 curB 指针,让curA指向B链表的头节点,curB指向A链表的头节点
ListNode tNode = curA;
curA = curB;
curB = tNode;
}
int dlength = lengthA - lengthB;
while (dlength != 0) {
curA = curA.next;
dlength--;
}
// (3)
while (curA != null) {
if (curA == curB) {
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
}
题目链接:142.环形链表II
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
解题思路:看到这道题目的第一想法是用快慢指针来找环,如果两者相遇则说明链表存在环。
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 index2;
}
}
return null;
}
}