# 金典问题

# 反转链表

反转一个单链表。

示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

// 方法一:迭代
var reverseList = function(head) {
  var prev = null;
  var curr = head;
  // 遍历链表,将链表的指针依次反转
  while (curr) {
    var temp = curr;
    curr = curr.next;
    temp.next = prev;
    prev = temp;
  }
  return prev;
};
// 方法二:递归
var reverseList = function(head) {
  if (!head) {
    return null;
  }
  var tail = head;
  function goNext(node) {
    if (node.next) {
      var temp = goNext(node.next);
      temp.next = node;
    } else {
      tail = node;
    }
    node.next = null;
    return node;
  }
  goNext(head);
  return tail;
};

# 移除链表元素

删除链表中等于给定值 val 的所有节点。

示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5

var removeElements = function(head, val) {
  var sentinel = { next: head };
  var curr = head;
  var prev = sentinel;
  while (curr) {
    if (curr.val === val) {
      prev.next = curr.next;
    } else {
      prev = curr;
    }
    curr = curr.next;
  }
  return sentinel.next;
};

# 奇偶链表

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

示例 1:
输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL

示例 2:
输入: 2->1->3->5->6->4->7->NULL
输出: 2->3->6->7->1->5->4->NULL

说明:
应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

// 方法一:拼接法,将奇数项和偶数项分开拼接,最后再将奇数链和偶数链链接
var oddEvenList = function(head) {
  if (!head) {
    return head;
  }
  var index = 1;
  var odd = null;
  var event = null;
  var curr = head;
  var eventHead = null;
  while (curr) {
    var temp = curr;
    curr = curr.next;
    temp.next = null;
    if (index % 2 !== 0) {
      // 奇数
      if (odd) {
        odd.next = temp;
      }
      odd = temp;
    } else {
      // 偶数
      if (event) {
        event.next = temp;
      } else {
        eventHead = temp;
      }
      event = temp;
    }
    index++;
  }
  odd.next = eventHead;
  return head;
};

# 回文链表

请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

// 方法一:将数值复制到数组后用双指针法
var isPalindrome = function(head) {
  var valList = [];
  var curr = head;
  while (curr) {
    valList.push(curr.val);
    curr = curr.next;
  }
  var res = true;
  for (var i = 0, j = valList.length - 1; i < j; i++, j--) {
    if (valList[i] !== valList[j]) {
      res = false;
      break;
    }
  }
  return res;
};
// 方法二:递归判断
var isPalindrome = function(head) {
  var frontHead = head;
  function goNext(node) {
    // 尾结点直接返回true
    if (node) {
      // 递归,如果递归的下一层返回false,即不是回文,本层也直接返回false
      if (!goNext(node.next)) {
        return false;
      }
      // 判断是否为回文
      if (node.val !== frontHead.val) {
        // 不是回文则返回false
        return false;
      }
      // frontHead指针从头开始遍历
      frontHead = frontHead.next;
    }
    // 尾结点直接返回true
    return true;
  }
  return goNext(head);
};
// 方法三:快慢指针
// 步骤:
// 1、利用快慢指针找到链表中点节点
// 2、反转后半段链表
// 3、遍历对比前后两段链表
// 4、还原链表
var isPalindrome = function(head) {
  if (!head || !head.next) {
    return true;
  }
  var slow = { next: head };
  var fast = { next: head };
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
  }
  // 前半段长度>=后半段
  var mind = slow.next;
  // 切断前后两段
  slow.next = null;
  // 新指针分别记录前后2段链表
  var link1 = head;
  var link2 = mind;
  function reverseLink(link) {
    var prev = null;
    var curr = link;
    while (curr) {
      var temp = curr;
      curr = curr.next;
      temp.next = prev;
      prev = temp;
    }
    return prev;
  }
  link2 = reverseLink(link2);
  var saveLink2 = link2;
  var res = true;
  while (link2) {
    if (link1.val === link2.val) {
      link1 = link1.next;
      link2 = link2.next;
    } else {
      break;
    }
  }
  if (link2) {
    res = false;
  }
  mind.next = reverseLink(saveLink2);
  return res;
};