每日一题:两两交换链表中的节点

150 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情

题目链接

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即只能进行节点交换)。

示例一

输入: head = [1,2,3,4]
输出: [2,1,4,3]

示例 2:

输入: head = []
输出: []

示例 3:

输入: head = [1]
输出: [1]

提示:

  • 链表中节点的数目在范围 [0, 100] 内
  • 0 <= Node.val <= 100

解题思路: (利用栈)

因为具有先进后出,后进先出的特性。我们就可以用一个stack,不断地迭代链表,每次取出两个节点放进stack里,放进去的时候是 1,2 拿出来的时候就是 2,1了。

再把这俩个节点连接起来,重复此逻辑不断的变遍历链表,我们就完成了节点两两反转的操作

代码: (Java实现)

public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }

        //用stack来保存每次迭代的两个节点
        Stack<ListNode> stack = new Stack<ListNode>();
        ListNode p = new ListNode(-1);
        ListNode cur = head;

        //节点head指向p指针,迭代结束后返回head.next即可
        head = p;
        while (cur != null && cur.next != null) {
            //将节点放进stack里
            stack.add(cur);
            stack.add(cur.next);
            
            //当前节点向右移动两位
            cur = cur.next.next;

            //从stack中弹出两个节点,用p节点指向新弹出的两个节点
            p.next = stack.pop();
            p = p.next;
            p.next = stack.pop();
            p = p.next;
            
        }
        
        //注意边界条件,无论链表是奇数还是偶数,都让它指向cur
        p.next = cur;
        
        //返回结果
        return head.next;
    }

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1),因为stack每次只存两个元素,所以复杂度依然是O(1)

提交结果

image.png

解题思路: (迭代法)

用迭代法要小心处理节点的指向

这里我们需要三个指针 slow,high,temp

我们举例来说,假设链表是:

1->2->3->4

迭代时,每次处理两个节点,第一轮为 slow指向1,high指向2

在第二轮时,slow指向3,high指向4

我们通过 slow.next = high.next,high.next = slow 就把两个节点反转了,于是1->2就变成2->1

但这里有一个要注意的地方,当进行到第二轮时,3—>4反转成4->3。根据题目要求,最终结果应该是2->1->4->3,但是,节点1并不能和节点4直接串起来,所以,这里我们就需要一个temp指针用来存放上一轮slow的位置,下一轮迭代时,将slow(节点1)指向节点4

代码: (Java实现)

class Solution {
    public ListNode swapPairs(ListNode head) {
        //增加一个虚节点进行处理
        ListNode p = new ListNode(-1);
        p.next = head;
        //创建slow,high,tmp三个指针
        ListNode slow = p;
        ListNode high = p;
        ListNode temp = p;
        
        while(high!=null && high.next!=null && high.next.next!=null) {
            //slow前进一位,high前进两位
            slow = slow.next;
            high = high.next.next;
            
            //假设链表是1->2->3->4,a指向1,b指向2
            //改slow和high的指向,于是就变成2->1
            //1是不能指向2的next,1应该指向4,而循环迭代的时候一次处理2个节点
            //1和2的关系弄清楚了,3和4的关系也能弄清楚,但需要一个指针来处理
            //2->1,4->3的关系,temp指针就是干这个用的
            temp.next = high;
            slow.next = high.next;
            high.next = slow;
            
            //现在链表就变成2->1->3->4
            //temp和high都指向1节点,等下次迭代的时候
            //a就变成3,b就变成4,然后tmp就指向b,也就是1指向4
            temp = slow;
            high = slow;
        }
        return p.next;
    }
}

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

提交结果

image.png