两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4] 输出:[2,1,4,3]
示例 2:
输入:head = [] 输出:[]
示例 3:
输入:head = [1] 输出:[1]
提示:
- 链表中节点的数目在范围
[0, 100]
内 0 <= Node.val <= 100
这题主要的思路就是任何完成节点的重新指向,主要的交换步骤如图。具体思路有了,就可以按照图示的方法来进行代码实现,可以用递归或者直接遍历来实现
/**
* 循环遍历实现
*
* @param head
* @return
*/
public ListNode swapPairs(ListNode head) {
ListNode dummyNote = new ListNode(-1, head);
ListNode currentNode = dummyNote;
while (currentNode.next != null && currentNode.next.next != null) {
ListNode tempNote = currentNode.next;
currentNode.next = currentNode.next.next;
tempNote.next = currentNode.next.next;
currentNode.next.next = tempNote;
currentNode = currentNode.next.next;
}
return dummyNote.next;
}
/**
* 递归实现
*
* @param head
* @return
*/
public ListNode swapPairs2(ListNode head) {
ListNode dummyNote = new ListNode(-1, head);
ListNode currentNote = dummyNote;
return swap(dummyNote,currentNote);
}
public ListNode swap(ListNode dummyNote,ListNode currentNote) {
while (currentNote.next == null || currentNote.next.next == null){
return dummyNote.next;
}
ListNode tempNote = currentNote.next;
currentNote.next = currentNote.next.next;
tempNote.next = currentNote.next.next;
currentNote.next.next = tempNote;
currentNote= currentNote.next.next;
return swap(dummyNote,currentNote);
}
删除链表的第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]
提示:
- 链表中结点的数目为
sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
这一题可以使用暴力解法实现,我们要说的是通过一次遍历来实现删除元素。说到删除元素应该先想到的是之前说到的虚拟头节点,这样删除头节点和其他节点都是相同的操作。因为我们无法知道删除倒数节点需要从头开始位移多少步,所以需要使用双指针先将preNode进行移位操作,然后currentNode还是指向虚拟节点,这样再同步位移,当preNode到最后一个节点的时候,这时候将currentNode的位置就是需要被删除的节点前一个节点的位置,进行删除操作即可
public ListNode removeNthFromEnd(ListNode head, int n) {
//已经给定n的范围,不需要判断n的值是否满足0-head.size之间
ListNode dummyHead = new ListNode(-1, head);
ListNode currentNode = dummyHead;
ListNode preNode = currentNode;
for (int i = 0; i < n; i++) {
preNode = preNode.next;
}
while (preNode.next != null){
currentNode = currentNode.next;
preNode = preNode.next;
}
if (currentNode.next != null){
currentNode.next = currentNode.next.next;
}
return dummyHead.next;
}
链表相交
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
图示两个链表在节点 c1
开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 输出:Intersected at '8' 解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。 在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 输出:Intersected at '2' 解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。 在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 输出:null 解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。 由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 这两个链表不相交,因此返回 null 。
提示:
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]
主要的解题思路是先将两个长度不一致的链表在都在同一个位置进行遍历,同步移位后判断两个节点是否相等,如果相同,则返回该链表,遍历完没有相同的节点,则返回null
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode countANode = headA;
ListNode countBNode = headB;
int lenA = 0;
int lenB = 0;
while (countANode != null) {
countANode = countANode.next;
lenA++;
}
while (countBNode != null) {
countBNode = countBNode.next;
lenB++;
}
ListNode maxList;
ListNode minList;
int diff = 0;
if (lenA > lenB) {
maxList = headA;
minList = headB;
diff = lenA - lenB;
} else {
maxList = headB;
minList = headA;
diff = lenB - lenA;
}
while (diff > 0) {
maxList = maxList.next;
diff--;
}
for (int i = 0; i < lenB; i++) {
if (maxList == minList) {
return minList;
}
maxList = maxList.next;
minList = minList.next;
}
return null;
}