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

文|Seraph

01 | 问题

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

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

示例:

给定 1->2->3->4, 你应该返回 2->1->4->3.

02 |解题

初解:

这里思路就是通过交换指向指针来变动两两前后节点的顺序。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head==nullptr)
            return nullptr;
        ListNode *cur = head;
        ListNode *next = cur->next;
        ListNode *result = next;
        ListNode *pre = nullptr;//用来记录两两节点的前一个节点
        while(next!=nullptr && cur!=nullptr)
        {
            cur->next = next->next;
            next->next = cur;
            if(pre!=nullptr)
            {
                 pre->next = next;
            }
        
            pre = cur;
            cur = cur->next;
            if(cur!=nullptr)
            {
                next = cur->next;
            }
        }
        return result?result:head;//判断是不是仅有一个节点。
    }
};

以上解法,交换和判断有点过多。看起来有点乱。
这里可以使用一个链表常用的方法减少头结点的特殊处理逻辑。在链表前再加一个空节点就可以了。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode *pre = new ListNode(0);
        pre->next = head;
        ListNode *p = pre;
        while(p->next!=nullptr && p->next->next!=nullptr)
        {
            ListNode *start = p->next;
            ListNode *end = p->next->next;
            start->next = end->next;
            end->next = start;
            p->next = end;
            p = start;
        }
        return pre->next;
    }
};

再想下,因为节点值是int的,不大,所以其实可以直接交换值,反而更简单。(后面仔细看了下,好像题目提示不能交换节点的值。。。)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head==nullptr || head->next == nullptr)
            return head;
        ListNode *cur = head;
        ListNode *next = cur->next;
        while(next!=nullptr && cur!=nullptr)
        {
            cur->val = cur->val ^ next->val;
            next->val = cur->val ^ next->val;
            cur->val = cur->val ^ next->val;
            
            cur = cur->next->next;
            if(cur != nullptr)
            {
                 next = cur->next;
            }
           
        }
        return head;
    }
};
终解:

大部分链表的题,都是能使用递归了,这题也不例外。
当写递归的时候,一定不要按迭代的思想去试图屡清楚,这样会相当煎熬。
只需按如下步骤:

  • 终止条件是什么?
  • 假设K+1步处理好了,怎么处理K步?
  • 返回值是什么?

每次写递归,写不出来,然后看别人怎么写的,都感觉自己是个傻子。而且还是心里没底,是不是完全符合题意。哈哈~,还是得多练,多想吧。。。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head==nullptr || head->next == nullptr)
            return head;
        ListNode *next = head->next;
        head->next = swapPairs(next->next);
        next->next = head;
        return next;
    }
};

03 | 积累知识点

  1. 链表处理时,为了统一处理逻辑,可以加一个空节点。
  2. 递归思想不要一步一步推导,只需要知道终止条件、前后推导就行。

官网链接 Leetcode No.24

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值