LeetCode算法学习之--链表--K个组翻转链表

386 阅读4分钟

大家好今天给大家分享下一道 LeetCode 困难难度 的题目[K 个一组翻转链表](leetcode-cn.com/problems/li…)

这里主要是分享思路和注释,供大家更好的理解题目解法,代码部分是参考LeetCode 转写成javascript 代码,

题目

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

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

示例1(图片转载LeetCode)

示例2(图片转载LeetCode)

示例1
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

示例2
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

示例3
输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]

分析

1.K是正整数

2.如果链表的长度不是k的整数倍 那么保留剩余节点的顺序

3.这道题和之前的两两交换相似,借鉴两两交换的思路设置dummy值

4.再利用之前学的翻转链表

解法

1.迭代

2.递归

解法一:迭代

代码借鉴 leetcode-cn.com/problems/re…

思路
1.先把链表分成k个元素一组
2.移动指针pre在 组的头部的上一个节点,指针end在组的尾部
3.翻转 组里面的元素
4.移动pre到下一个组的头部上一个节点,end 到下一个组的尾部
*/

var reverseKGroup = function (head, k) {
  let dummy = new ListNode(0);
  dummy.next = head;
  //设置 2个指针 pre 和end
  let pre = dummy;
  let end = dummy;

  while (end.next !== null) {
    //   把end 移动到组的尾部
    end = reachKNode(end, k);
    // 如果有任何end等于undefined的情况 这说明,剩余的节点已经不够K个
    // 直接结束循环
    if (!end) break;

    // 确定组中的开始节点和下一个组的开始节点
    const start = pre.next;
    const next = end.next;
    // 断开组中最后一个节点的末尾,方便翻转链表
    end.next = null;
    // 翻转后start就变成了末尾
    pre.next = reverse(start);
    // 让start 指向下一个组的开始的节点
    start.next = next;

    // 把pre 和 end 指针指向翻转后的链表的最后一个节点,
    // 为下次迭代做准备
    pre = start;
    end = pre;
  }

  return dummy.next;

  //让end 到组的末尾
  function reachKNode(node, k) {
    while (k > 0) {
      // 如果有等于零的就返回false
      if (!node) {
        return false;
      }
      node = node.next;
      k--;
    }

    return node;
  }

    //翻转链表 迭代法
    function reverse(node) {
      let pre = null,
        cur = node;
      while (cur) {
        let n = cur.next;
        cur.next = pre;

        //  移动指针
        pre = cur;
        cur = n;
      }
      return pre;
    }

};

1.png

解法二:递归

思路
和迭代一样 只是reverse使用了递归的解法
var reverseKGroup = function (head, k) {
  let dummy = new ListNode(0);
  dummy.next = head;
  //设置 2个指针 pre 和end
  let pre = dummy;
  let end = dummy;

  while (end.next !== null) {
    //   把end 移动到组的尾部
    end = reachKNode(end, k);
    // 如果有任何end等于undefined的情况 这说明,剩余的节点已经不够K个
    // 直接结束循环
    if (!end) break;

    // 确定组中的开始节点和下一个组的开始节点
    const start = pre.next;
    const next = end.next;
    // 断开组中最后一个节点的末尾,方便翻转链表
    end.next = null;
    // 翻转后start就变成了末尾
    pre.next = reverse(start);
    // 让start 指向下一个组的开始的节点
    start.next = next;

    // 把pre 和 end 指针指向翻转后的链表的最后一个节点,
    // 为下次迭代做准备
    pre = start;
    end = pre;
  }

  return dummy.next;

  //让end 到组的末尾
  function reachKNode(node, k) {
    while (k > 0) {
      // 如果有等于零的就返回false
      if (!node) {
        return false;
      }
      node = node.next;
      k--;
    }

    return node;
  }

  // 递归法
  function reverse(node) {
    if (!node || !node.next) {
      return node;
    }

    const endNode = reverse(node.next);
    node.next.next = node;
    node.next = null;
    return endNode;
  }
};

2.png

总结

这道题是对之前的两两交换和翻转链表的一种综合考察,有兴趣的可以看看我专栏中分享的两两交换和翻转链表

大家可以看看我分享的一个专栏(前端搞算法)里面有更多关于算法的题目的分享,希望能够帮到大家,我会尽量保持每天晚上更新,如果喜欢的麻烦帮我点个赞,十分感谢

文章内容目的在于学习讨论与分享学习算法过程中的心得体会,文中部分素材来源网络,如有侵权,请联系删除,邮箱 182450609@qq.com