leetcode 算法题(链表):环形链表、环形链表II、反转链表、两两交换链表中的节点

184 阅读2分钟

141. 环形链表

image.png

解题思路
  • 需要了解链表基础
  • 使用快慢指针,一个一次走两步、一个一次走一步,如果相遇说明有环
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    if(!head) {return false}
    let p = head;
    let fast = head.next;
    while(fast && fast.next) {
        if(p === fast) {
            return true;
        }
        p = p.next;
        fast = fast.next.next;
    }
    return false;    
};
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    if(!head) {return false}
    let p = head;
    let fast = head.next;
    // 稍许不同的写法
    while(p != fast && fast && fast.next) {
        if(p === fast) {
            return true;
        }
        p = p.next;
        fast = fast.next.next;
    }
    return p === fast;
};

142. 环形链表 II

image.png

解题思路
  • 先使用快慢指针找到相遇位置
  • 如果找到,相遇位置,快慢指针都开始使用相同的速度前进,如果再次相遇,就说明是环的起点

image.png

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function(head) {
  if(!head || !head.next) {
      return null;
  }
  let p = head.next;
  let fast = head.next.next;
  while(fast !== p && fast && fast.next ) {
      p = p.next;
      fast = fast.next.next;
  }
  if(fast !== p) {
      return null;
  }
  p = head;
  while(p !== fast && p) {
      p = p.next;
      fast = fast.next;
  }
  return p;
};

206. 反转链表

image.png

解题思路
  • 维护两个指针,依次反转节点 入: 1->null 第二次 2->1->null
  • 依次类推达到翻转所有节点
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
if(!head || !head.next) {
    return head;
}
    let pre = null;
    let cur = head;
    while(cur) {
        // 把当前节点的下个节点记录下来
        const next = cur.next;
        // 把当前节点的前个节点 反转 成下个节点
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
};

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/** 
 * 递归解法   
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
   if(!head || !head.next) {
     return head;
   }
    let pre = head;
    let tail = head.next;
    console.log(pre.val,tail.val,'up')
    let p = reverseList(head.next);
    console.log(pre.val,tail.val,'down')
    pre.next = null;
    tail.next = pre;
 return p;
};

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

image.png

解题思路
  • 定义一个函数,使用函数对于节点和它的下一个节点进行交换
  • 比如 helper(1) 处理 1 -> 2,并且把交换变成 2 -> 1 的尾节点 1next继续指向 helper(3)也就是交换后的 4 -> 3
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var swapPairs = function(head) {
    if(!head || !head.next) {return head}

    // 使用helper进行两两反转
    const helper = (node) => {
        const tempNext = node.next;
        if(tempNext) {
            const tempNextNext = node.next.next;
            node.next.next = node;
            if(tempNextNext) {
                node.next = helper(tempNextNext)
            } else {
                node.next = null;
            }
        }
        return tempNext || node;
    }

    return helper(head)
};