LeedCode 143:重排链表

重排链表

题目描述:

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

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

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

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

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

LeedCode 143:重排链表_第1张图片

链接:

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;
};

你可能感兴趣的:(LeetCode,链表,重排链表)