每日一恋 - LeetCode 24 & 25. 交换链表中的节点

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

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

示例:

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

说明:

  • 你的算法只能使用常数的额外空间。
  • 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

解法一

迭代版,设置一个指针 p 每次处理其后面的两个节点,若存在两个则进行交换,并更新 p 指针;若不足两个则结束处理。

public ListNode swapPairs(ListNode head) {

   ListNode dummyHead = new ListNode(-1);
    dummyHead.next = head;

    ListNode p = dummyHead;

    while (p.next != null && p.next.next != null) {
        ListNode node1 = p.next;
        ListNode node2 = p.next.next;
        node1.next = node2.next;
        node2.next = node1;
        p.next = node2;
        p = node1;
    }

    return dummyHead.next;
}

解法二

递归版,递归处理每一对节点,直到只有一个节点或者没有节点为止。

 public ListNode swapPairs(ListNode head) {
    if ((head == null)||(head.next == null))
        return head;
    ListNode n = head.next;
    head.next = swapPairs(head.next.next); // 第一个节点连接后面那对节点
    n.next = head; // 第二个节点指向第一个节点
    return n; // 返回第二个节点
}

25. k个一组翻转链表

给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。

示例 :

给定这个链表:1->2->3->4->5

当 k = 2 时,应当返回: 2->1->4->3->5

当 k = 3 时,应当返回: 3->2->1->4->5

说明 :

  • 你的算法只能使用常数的额外空间。
  • 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

解法一

与上一题不同的是,这题要求每k个节点进行反转。一个思路是用迭代法,每次进行反转之前,先判断是否有足够的k个节点,若不够则直接返回。否则说明有 k 个节点,只要依次反转后面的 k 个节点,更新指针,接着对下一组子链表的数量进行判断。

public ListNode reverseKGroup(ListNode head, int k) {

    ListNode dummyHead = new ListNode(-1);
    dummyHead.next = head;

    ListNode pre = dummyHead; // 定义:每组的前驱结点,pre.next指向的总是每组的开头结点
    ListNode cur = pre.next; // 定义:初始时,每组的头结点,cur.next指向的总是下一个待反转结点
    ListNode end = dummyHead; // 定义:找到每组的最后一个元素
    // 开始反转,将每个待反转结点都插入头,作为头结点
    while (true) {

        end = pre; // 看余下的节点是否存在k个
        int c = k;
        while (end.next != null && c != 0) {
            end = end.next;
            c --;
        }
        // 不存在则结束循环
        if ( c > 0 ) break;

        // 存在则开始遍历k个节点的一组
        int s = k;
        while (--s > 0) { // 当头结点已经是初始状态下每组的最后一个结点时,结束循环,本组的链表倒转完成

            ListNode node2 = cur.next;
            cur.next = node2.next; // 这里维护了cur的定义
            node2.next = pre.next; // 待插入结点指向目前每组的头结点
            pre.next = node2; // 更新每组的头结点
        }

        pre = cur; // 注意pre的定义, cur结束时正好符合pre的定义
        cur = pre.next;
    }
    return dummyHead.next;
}

解法二

这一题也可以用递归的解法,首先判断是否有足够的k个节点,若不够则直接返回。然后在反转时,head指针始终指向待反转链表的第一个节点,每次将其指向已经处理好的子问题的 pre 指针,更新 pre 和 head,继续反转完余下的节点。

public ListNode reverseKGroup(ListNode head, int k) {
    // 判断是否有足够的k个节点,若不够则直接返回
    ListNode node = head;
    int count = 0;
    while (count < k) {
        if(node == null)return head;
        node = node.next;
        count++;
    }
    //pre 指针指向子问题的答案
    ListNode pre = reverseKGroup(node, k);
    // 反转k个节点
    while (count > 0) {
        ListNode next = head.next;
        head.next = pre;
        pre = head;
        head = next;
        count = count - 1;
    }
    return pre;
}

如果文章里有说得不对的地方请前辈多多指正~ 与君共勉~

猜你喜欢

转载自blog.csdn.net/smartnijun/article/details/81776203