今天是第 天刷leetcode,立个flag,打卡60天。
算法挑战链接
力扣 http://24. 两两交换链表中的节点
http://24. 两两交换链表中的节点
第一想法
看到题目的第一想法是交换节点,于是赶紧拿出草稿本画了出来。这不简简单单。
1 -> 2 ->3 ->.....
已有的条件:head = node(1)
我只需要将head的节点后的2节点记录下来,然后将head.next 赋值给 3 节点。将2.next 赋值给head节点,这样就完成交换了。
跟随者思路写出代码后提交失败了。~~
主要失败的原因是:head.next 赋值给3节点这个是错误的,因为3节点需要和后面的节点进行交换,因此head.next 应该赋值给交换后的节点。
看完代码随想录之后的想法
使用递归来完成这道题目是一个很不错的选择。
先呈上代码:
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode next = head.next;
        //进行递归
        ListNode newNode = swapPairs(next.next);
        //进行交换
        head.next = newNode;
        next.next = head;
        return next;
    }
}为啥说递归是一个不错的选择,因为我们知道一个局部的操作,这个局部的操作依赖于下一个局部的操作,于是我们可以使用递归,让下一个局部的操作先完成,然后给到我们需要的数据,我们在进行当前的局部操作即可。
当然不递归也是可以完成的。
在不递归的情况下哎我们完成完成交换需要的步骤是三步(如下图)
只需要遍历节点,不断的重复这三个步骤即可完成。(需要注意的点:首节点的操作是不一样,如果不想单独写首节点的操作,可以加入一个哑节点,让后续的操作可以一致。)
 

代码如下:
class Solution {
  public ListNode swapPairs(ListNode head) {
        ListNode dumyhead = new ListNode(-1); // 设置一个虚拟头结点
        dumyhead.next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
        ListNode cur = dumyhead;
        ListNode temp; // 临时节点,保存两个节点后面的节点
        ListNode firstnode; // 临时节点,保存两个节点之中的第一个节点
        ListNode secondnode; // 临时节点,保存两个节点之中的第二个节点
        while (cur.next != null && cur.next.next != null) {
            temp = cur.next.next.next;
            firstnode = cur.next;
            secondnode = cur.next.next;
            cur.next = secondnode;       // 步骤一
            secondnode.next = firstnode; // 步骤二
            firstnode.next = temp;      // 步骤三
            cur = firstnode; // cur移动,准备下一轮交换
        }
        return dumyhead.next;  
    }
}
实现过程中遇到哪些困难
今天在完成题目的过程中忽略掉了后续节点变化的一个流程。导致题目一直没有做对。
今日收获
递归怎么写?写递归前需要明白三点
- 退出递归的条件(递归第一件要完成的事情)
- 进入递归的条件和返回值
- 获取到下一个递归值后的操作
确定好之后,写递归会比较清晰。
用今天这道题来看,我们对应这三个点分别是:
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        //退出递归的条件(递归第一件要完成的事情)
        if (head == null || head.next == null) {
            return head;
        }
        ListNode next = head.next;
        //进入递归的条件和返回值
        //进行递归
        ListNode newNode = swapPairs(next.next);
        获取到下一个递归值后的操作
        //进行交换
        head.next = newNode;
        next.next = head;
        return next;
    }
}

![[Linux笔记]常见命令(持续施工)](https://img-blog.csdnimg.cn/880deb62f4704ccba141f5827eef335e.png)
















