Leetcode1721交换链表中的节点

题目描述:
给链表头节点 head 和 整数 k, 交换链表正数第k个节点和倒数第k个节点,返回头节点。
示例:
输入:head = [7,9,6,6,7,8,3,0,9,5], k = 5
输出:[7,9,6,6,8,7,3,0,9,5]
算法1:(交换两个节点)

交换节点需要找到要交换的节点的前一个节点。

1、遍历链表,得到链表总长度 n。
2、找到正数第k个节点的前一个节点 记为 p,也即走k-1步。
3、找到倒数第k个节点的的前一个节点 记为 q,走 n-k 步。
4、交换两个节点,需要维护四个节点,节点 p, q, 要交换的左节点 ptl, 要交换的右节点的下一个节点 ptr;
注意: 有两种例外情况需要判掉,否则会造成链表指针自己指向自己的问题。
    4.1 特判: 当正数第 k 个节点在倒数第 k 个节点的相邻左边的时候
    4.2 特判: 当正数第 k 个节点在倒数第 k 个节点的相邻右边的时候
其实这里可以直接特判当 p 和 q 相邻的时候,直接 reverse 一下两个节点会少一点代码量。
时间复杂度分析:

O(N)

C++代码实现:
class Solution {
public:
    ListNode* swapNodes(ListNode* head, int k) {
        if(!head ||!head->next) return head;
        ListNode* dummy = new ListNode(-1);
        dummy->next = head;
        // 计算链表总长度
        auto ptr = head;
        int n = 0;
        for(;ptr;ptr=ptr->next) n++;

        // 正数第k个节点前一个节点,倒数第k个节点后一个节点
        auto p = dummy, q = dummy;
        for(auto i = 0; i < k - 1; i++) p = p->next;
        int cnt = n - k;
        for(auto i = 0; i < cnt; i++)   q = q->next;
        
        // 特判 当正数第k个节点在倒数第k个节点左边相邻
        if(p->next == q){
            auto temp = q->next->next;
            p->next = q->next;
            q->next->next = q;
            q->next = temp;
        }
        // 特判 当正数第k个节点在倒数第k个节点右边相邻
        else if(q->next == p){
            auto temp = p->next->next;
            q->next = p->next;
            p->next->next = p;
            p->next = temp;
        }
        else{
            ListNode* ptl = p->next;
            ListNode* ptr = q->next->next;
            p->next = q->next;
            q->next->next = ptl->next;
            q->next = ptl;
            ptl->next = ptr;
        }
        return dummy->next;
    }
};
算法2:交换两个节点值

这种方式很取巧,之前很多题都特意说不能仅交换节点值,面试时可以跟面试官交流一下这种方法是否可行。

代码实现:
class Solution {
public:
    ListNode* swapNodes(ListNode* head, int k) {
        if(!head ||!head->next) return head;
        ListNode* dummy = new ListNode(-1);
        dummy->next = head;
        // 计算链表总长度
        auto ptr = head;
        int n = 0;
        for(;ptr;ptr=ptr->next) n++;

        // 正数第k个节点前一个节点,倒数第k个节点后一个节点
        auto p = dummy, q = dummy;
        for(auto i = 0; i < k - 1; i++) p = p->next;
        int cnt = n - k;
        for(auto i = 0; i < cnt; i++)   q = q->next;
        // 交换节点值
        swap(p->next->val, q->next->val);
        return dummy->next;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值