24. Swap Nodes in Pairs Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem without modifying the values in the list's nodes (i.e., only nodes themselves may be changed.)
题目要求每两个节点要互相对换,且不允许改变节点的值,意味着需要交换节点位置。 首先肯定是要考虑奇数与偶数数量的节点,但奇数节点的最后一个可以留下不管,并不需要特殊处理。 然后对于需要交换的两个节点A和B,若要完成交换,需要将二者之前的prev节点的next值也做更新,这样的话,使用一个虚假头节点会有帮助。
代码:
/**
* 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 dummy = new ListNode(-1, head);
ListNode prev = dummy;
ListNode cur = head;
while(cur != null && cur.next != null) {
ListNode temp = cur.next.next;
prev.next = cur.next;
cur.next.next = cur;
cur.next = temp;
prev = cur;
cur = temp;
}
return dummy.next;
}
}
19. Remove Nth Node From End of List
Given the head of a linked list, remove the nth node from the end of the list and return its head.
题目要求删除倒数第n个节点,那么就需要知道第n个节点的前一个节点。考虑到第n个节点也可能会是头节点,加入虚假头节点会有帮助。 O(n)做法的话,要维护一个n长度滑动窗口,在窗口末端指向尾节点的时候,窗口起始端会指向倒数第n个节点。但实际需要的是倒数第n+1个节点,所以滑动窗口的长度应为n+1;在代码中,len的长度为n+1
代码:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(-1, head);
ListNode fast = head;
ListNode slow = dummy;
int len = 0;
while(fast != null) {
if(len < n) {
fast = fast.next;
len++;
}
else if (len == n){
fast = fast.next;
slow = slow.next;
}
}
slow.next = slow.next.next;
return dummy.next;
}
}
160. Intersection of Two Linked Lists
Given the heads of two singly linked-lists headA and headB, return the node at which the two lists intersect. If the two linked lists have no intersection at all, return null.
For example, the following two linked lists begin to intersect at node c1:
The test cases are generated such that there are no cycles anywhere in the entire linked structure.
Note that the linked lists must retain their original structure after the function returns.
Custom Judge:
The inputs to the judge are given as follows (your program is not given these inputs):
intersectVal- The value of the node where the intersection occurs. This is0if there is no intersected node.listA- The first linked list.listB- The second linked list.skipA- The number of nodes to skip ahead inlistA(starting from the head) to get to the intersected node.skipB- The number of nodes to skip ahead inlistB(starting from the head) to get to the intersected node.
The judge will then create the linked structure based on these inputs and pass the two heads, headA and headB to your program. If you correctly return the intersected node, then your solution will be accepted.
由于链表只要相交了之后,就会一直相交,所以在判断已经相交之后,没必要做后续判断。 问题是如何让两个链表的扫描指针相遇在交点。 方法是设两者较短链表A长度为n,则链表A从头部开始,链表B则从倒数第n个节点开始。就可以保证两者在相交的前提下同步相遇。 所以需要先找出两个链表的长度a,b,然后定义起始节点startA和startB,从上述位置出发。 相遇即相交,否则返回null
代码:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lena = 0;
int lenb = 0;
ListNode cur1 = headA;
ListNode cur2 = headB;
while(cur1 != null) {
cur1 = cur1.next;
lena++;
}
while(cur2 != null) {
cur2 = cur2.next;
lenb++;
}
cur1 = headA;
cur2 = headB;
if(lena > lenb) {
int diff = lena - lenb;
while(diff > 0) {
cur1 = cur1.next;
diff--;
}
}
else if (lena < lenb) {
int diff = lenb - lena;
while(diff > 0) {
cur2 = cur2.next;
diff--;
}
}
while(cur1 != null && cur2 != null) {
if(cur1 == cur2) {
return cur1;
}
else {
cur1 = cur1.next;
cur2 = cur2.next;
}
}
return null;
}
}
142. Linked List Cycle II
Given the head of a linked list, return the node where the cycle begins. If there is no cycle, return null.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail's next pointer is connected to (0-indexed). It is -1 if there is no cycle. Note that pos is not passed as a parameter.
Do not modify the linked list.
判断链表有环不难,快慢指针即可,只要能相遇,就能判断有环。麻烦的是找到环的起始点。
如图。有2*(x+y) = n(y+z) + x + y, 右边为快指针遍历的节点数,左边为慢指针的节点数 * 2,因为快指针走两步,慢指针走一步。
则有: x + y = ny + nz => x = (n-1) y + nz
n - 1 时,有x=z; n > 1 时,有x = n(y+z) - y = (n-1)(y+z) + z, 意味着x等于n-1圈的长度加上z。那么, 若有一个节点从头节点出发,另一个节点从meet point出发,则这两个节点会在环形入口节点相遇。n=1时有同样结论。
关于为什么2*(x+y) = n(y+z) + x + y, 这意味着慢指针会在进入环的第一圈就遇上快指针。由于当慢指针进入环入口时,若快指针也在入口,那没什么好说的,直接相遇了。若快指针不在入口,则每次循环,快指针都会向慢指针靠近1.取极端情况,设慢指针到达入口时,快指针正好在慢指针前一节点。则快指针需要环的长度m - 1次循环追上慢指针,慢指针此时也只移动了m - 1,并没有超过一圈,于是此前的式子成立。
代码:
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode slow = head;
ListNode meet = null;
Boolean bstart = true;
while(fast != null && fast.next != null) {
if(fast == slow && !bstart) {
meet = fast;
break;
}
bstart = false;
fast = fast.next.next;
slow = slow.next;
}
if(meet == null) {
return null;
}
ListNode start1 = head;
ListNode start2 = meet;
while(start1 != start2) {
start1 = start1.next;
start2 = start2.next;
}
return start1;
}
}