这题使用虚拟头结点会更好做,因为有虚拟头结点我们交换结点的时候步骤会更加清晰。
操作此类有指针类型的题目要注意:1.画图避免混乱 2.注意指针先后顺序
class Solution { public ListNode swapPairs(ListNode head) { ListNode dumyhead = new ListNode(-1); // 设置一个虚拟头结点 dumyhead.next = head; // 将虚拟头结点指向head,这样方面后面做删除操作 ListNode cur = dumyhead; ListNode temp; // 临时节点,保存两个节点后面的节点 ListNode firstnode; // 临时节点,保存两个节点之中的第一个节点 ListNode secondnode; // 临时节点,保存两个节点之中的第二个节点 while (cur.next != null && cur.next.next != null) { temp = cur.next.next.next; firstnode = cur.next; secondnode = cur.next.next; cur.next = secondnode; // 步骤一 secondnode.next = firstnode; // 步骤二 firstnode.next = temp; // 步骤三 cur = firstnode; // cur移动,准备下一轮交换 } return dumyhead.next; } }
这题在考408数据结构的时候有印象也有类似的算法,有个很巧妙的解法就是利用双指针同时指向链表头,然后快指针先走n步,等到快指针走到第n个结点时,处于头结点的慢指针开始和快指针同时往后走,直到快指针把整个链表表走完停止,这时就会发现慢指针刚好停留在第n-1个结点上,此时我们只需要令慢指针的下一个结点指向下下一个位置的结点即可删除掉这个n号元素,也就是slow.next = slow.next.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 removeNthFromEnd(ListNode head, int n) { ListNode dummyNode = new ListNode(0); dummyNode.next = head; ListNode slowIndex = dummyNode; ListNode fastIndex = dummyNode; for(int i = 0; i < n; i ++){ fastIndex = fastIndex.next; } while(fastIndex.next != null){ slowIndex = slowIndex.next; fastIndex = fastIndex.next; } slowIndex.next = slowIndex.next.next; return dummyNode.next; } }
这题思路类似上一题,求两个链表的相交结点,我们可以先找到两个链表之间的长度差gap,然后选择让较长的那个链表指针先走gap步,接着再两个链表指针同时走动,当找到一个点是A=B的时候说明这个结点就是链表相交点。
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ 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; } }
public class Solution { public ListNode detectCycle(ListNode head) { ListNode slow = head; ListNode fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) {// 有环 ListNode index1 = fast; ListNode index2 = head; // 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口 while (index1 != index2) { index1 = index1.next; index2 = index2.next; } return index1; } } return null; } }