LeedCode 143:重排链表

重排链表

题目描述:

给定一个单链表 L 的头节点 head ,单链表 L 表示为: 

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 

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

你应当 保留 两个分区中每个节点的初始相对位置。

链接:

143. 重排链表 - 力扣(LeetCode) (leetcode-cn.com) 

解题思路

思路一:利用数组

利用数组可以直接按顺序访问指定元素,重建该链表即可

/**
 * @param {ListNode} head
 * @return {void} Do not return anything, modify head in-place instead.
 */
var reorderList = function(head) {
  if (head === null || head.next === null) {
    return head;
  }
  var list = [], curr = head;
  while(curr !== null) {
    list.push(curr);
    curr = curr.next;
  }
  var i = 0, j = list.length - 1;
  while (i < j) {
    list[i].next = list[j];
    i++;
    if (i == j) {
      break;
    }
    list[j].next = list[i];
    j--;
  }
  list[i].next = null;
};

时间复杂度: O(n)  

空间复杂度: O(n)

思路二:寻找链表中点 + 反转链表 + 合并链表

目标链表即为将原链表的左半端和反转后的右半端合并后的结果

可划分为三步:

  1. 利用快慢指针找到原链表的中点(参考「876. 链表的中间结点」)
  2.  将原链表的右半段反转(参考「206. 反转链表」)

  3. 合并左右两段链表

var reorderList = function (head) {
  if (head === null || head.next === null) {
    return head;
  }
  // 1. 找中点,使用 fast,slow 快慢双指针法,奇数个节点找到中点,偶数个节点找到中心左边的节点
  var slow = head,
    fast = head.next;
  while (fast != null && fast.next != null) {
    slow = slow.next;
    fast = fast.next.next;
  }
  // 2. 断开中点,反转后半部分
  var head2 = null,
    next = slow.next;
  slow.next = null;
  slow = next;
  while (slow != null) {
    next = slow.next;
    slow.next = head2;
    head2 = slow;
    slow = next;
  }

  // 3. 合并链表head和head2
  var curr = head;
  var curr2 = head2;
  while (curr != null && curr2 != null) {
    next = curr.next;
    curr.next = curr2;
    curr2 = curr2.next;
    curr.next.next = next;
    curr = next;
  }
};

时间复杂度: O(n) 

空间复杂度: O(1)

上面代码也可以按功能分出以下代码:

/**
 * @param {ListNode} head
 * @return {void} Do not return anything, modify head in-place instead.
 */
var reorderList = function (head) {
  if (head === null || head.next === null) {
    return head;
  }
  var mid = middleNode(head);
  var l1 = head;
  var l2 = mid.next;
  mid.next = null;
  l2 = reverseList(l2);
  mergeList(l1, l2);
};

// 合并
var mergeList = function (list1, list2) {
  var tmp1, tmp2;
  while (list1 != null && list2 != null) {
    tmp1 = list1.next;
    tmp2 = list2.next;

    list1.next = list2;
    list1 = tmp1;

    list2.next = list1;
    list2 = tmp2;
  }
};


// 反转链表
var reverseList = function (head) {
  var prev = null,
    curr = head,
    next = null;
  while (curr != null) {
    next = curr.next;
    curr.next = prev;
    prev = curr;
    curr = next;
  }
  return prev;
};

// 获取中间节点, 奇数个节点找到中点,偶数个节点找到中心左边的节点
var middleNode = function (head) {
  if (head === null) {
    return null;
  }
  let slow = head,
    fast = head.next;
  while (fast !== null && fast.next !== null) {
    fast = fast.next.next;
    slow = slow.next;
  }
  return slow;
};

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值