leetcode刷题:链表04 (两两交换链表中的节点)

75 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

24. 两两交换链表中的节点

力扣题目链接

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

24.两两交换链表中的节点-题意

package com.programmercarl.linkedlist;

import com.programmercarl.linkedlist.domain.ListNode;

import java.util.List;

/**
 * @ClassName SwapNodesInPairs
 * @Descriotion TODO
 * @Author nitaotao
 * @Date 2022/5/10 11:16
 * @Version 1.0
 **/
public class SwapNodesInPairs {
    public static void main(String[] args) {
        ListNode node8 = ListNode.builder().val(8).next(null).build();
        ListNode node7 = ListNode.builder().val(7).next(node8).build();
        ListNode node6 = ListNode.builder().val(6).next(node7).build();
        ListNode node5 = ListNode.builder().val(5).next(node6).build();
        ListNode node4 = ListNode.builder().val(4).next(node5).build();
        ListNode node3 = ListNode.builder().val(3).next(node4).build();
        ListNode node2 = ListNode.builder().val(2).next(node3).build();
        ListNode node1 = ListNode.builder().val(1).next(node2).build();
        System.out.println(swapPairs(node1));
    }

    /**
     * 虚拟头结点
     * 一共需要四个指针
     * 当前结点前一个结点 当前结点 当前结点后一个结点 当前结点后第二个结点
     *
     * @param head
     * @return
     */
    public static ListNode swapPairs(ListNode head) {
        //判断是否是空头结点
        if (head == null) {
            return null;
        }

        //当前结点
        ListNode curNode = head;
        //设置虚拟头结点
        ListNode preHead = new ListNode(0, head);
        //当前结点的前一个结点的位置,初始值代表虚拟头结点
        ListNode preCurNode = preHead;
        while (curNode != null) {
            if (curNode.next == null) {
                //如果当前结点是最后一个结点
                return preHead.next;
            }
            //当前结点还有下一个结点
            ListNode nextNode = curNode.next;
            //当前结点的下下个结点,这个可能为null
            ListNode thirdNode = nextNode.next;

            //当前结点的前一个结点位置后移
            preCurNode.next = nextNode;
            //2->1
            nextNode.next = curNode;
            //1->3
            curNode.next = thirdNode;

            //当前结点的前一个结点位置后移
            preCurNode = curNode;

            //当前结点后移
            curNode = curNode.next;
        }
        return preHead.next;
    }
}

感觉这题还是蛮难的,至少对我来说。 总体思路,抽象出来四个指针 preCurNode 当前结点的前一个结点 curNode 当前结点 nextNode 当前结点未交换时的下一个结点 thirdNode 当前结点未交换时的下下个结点 做了得有10小时。看题解都看好久,都不容易。 有一点要注意的就是preCurNode,也是头疼我最久,看的最困难的地方 这个结点代表当前结点的前一个结点的位置,这样单看谁都懂什么意思,具体模拟时就不容易理解是干嘛的了。 第一次,初始化preCurNode值时,给的位置是虚拟头结点的位置,因为当前结点为第一个结点,前一个结点不存在。在第一次循环中,它的位置变化了两次,第一次变化 preCurNode.next = nextNode;此时相当于preHead.next=nextNode,因为此时preCurNode代表虚拟头结点preHead。这也是为什么最后返回preHead.next的原因。此时preCurNode就是preHead。第二次后移,也就是 preCurNode = curNode,它就不再是代表虚拟头结点preHead了,是代表1号结点的位置,而之后 curNode = curNode.next,即当前结点后移一位到3,又因为1->3,则preCurNode再次代表了当前结点的前一个结点,相当于虚拟头结点->1,只不过这次是1->3,此时curNode为3. 在这里插入图片描述