Leetcode 1721. Swapping Nodes in a Linked List

题目

在这里插入图片描述

解析

这个题目有如下的几个问题需要解决:

  • 如何在遍历链表时找到两个需要被交换的节点位置
    从头开始的第k个节点很好找,从结尾开始的第k个节点比较难找。比较笨的办法是先遍历一边列表,拿到长度,根据长度确定后面那个的位置。比较聪明的办法在下面解法会讲到
  • 找到后如何交换
    交换的话就会需要定位到两个节点分别的前后节点,实际上只需要两个节点的前面节点,后面可以通过next得到
  • 如何处理特殊情况
    有三种特殊情况需要处理

解法1:交换值

首先这边讲下比较聪明的定位从结尾开始的第k个节点。第一种方法:先便利找到顺向的第k个节点,从这个结点开始,向后走到结尾的步数(len-k)正好能让头节点走到逆向的第k节点。第二种方法·:记录走的步数cnt,如果步数小于k,移动头节点直到找到顺向第k个节点;如果步数大于k,移动头节点直到找到逆向第k个节点(刚好会是len-k步);两种方法本质还是一样的
然后暴力的直接交换两个节点的位置。当然这是一种接近作弊的解法,不能体现这道题目的精髓

class Solution {
public:
    ListNode* swapNodes(ListNode* head, int k) {
        if(!head || !head->next){
            return head;
        }
        ListNode* left = head;
        ListNode* right = head;
        
        // find the kth node from beginning
        for(int i=1;i<k;i++){
            left = left->next;
        }
        // find the kth node from the end
        ListNode* curr = left;
        while(curr->next){
            curr = curr->next;
            right = right->next;
        }
        
        /* 
        // alternative way of finding two nodes
        int cnt = 1;
        ListNode* curr = head;
        while(curr){
            if(cnt < k){
                left = left->next;
            }
            if(cnt > k){
                right = right->next;
            }
            curr = curr->next;
            cnt++;
        }
        */
        
        int tmp_val = left->val;
        left->val = right->val;
        right->val = tmp_val;
        return head;
        
    }
};

解法2:实际交换节点

通过keep track of两个节点的前面节点来做到交换
难点在于需要处理三种特殊情况,在下面代码中都有详细注释。主要是两个节点相邻的特殊情况以及k超过一半的链表长度的特殊情况

class Solution {
public:
    ListNode* swapNodes(ListNode* head, int k) {
        if(!head || !head->next){
            return head;
        }
        // define dummy node for return the result
        ListNode* dummy = new ListNode(-1);
        dummy->next = head;
        
        // define the target left node to be swapped and the node before
        ListNode* preLeft = dummy;
        ListNode* left = head;
        // define the target right node to be swapped and the node before
        ListNode* preRight = dummy;
        ListNode* right = head;
        
        // find the the kth node from the beginning
        for(int i=1;i<k;i++){
            preLeft = preLeft->next;
            left = left->next;
        }
        // find the kth node from the end
        // trick here is that if the right start from the head of the list, when the left node reaches the end node, the right reaches the kth last node
        ListNode* curr = left;
        while(curr->next){
            curr = curr->next;
            preRight = preRight->next;
            right = right->next;
        }
        
        if(right == preLeft){
            // note the the 1 <= k <= n, so that the right node can be on the left of left node
            // ...preRight->right->left...
            right->next = left->next;
            preRight->next = left;
            left->next = right;
        }else if(left == preRight){
            // ...preLeft->left->right...
            left->next = right->next;
            preLeft->next = right;
            right->next = left;
        }else{
            // normal case:...preLeft->left->...->preRight->right... or ...preRight->right->...->preLeft->left...
            ListNode* tmp = left->next;
            left->next = right->next;
            preRight->next = left;
            preLeft->next = right;
            right->next = tmp;
        }
        return dummy->next;
        
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值