LeetCode刷题(4)链表

160 阅读4分钟

这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战

160. 相交链表

leetcode-cn.com/problems/in…

描述

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。

如果两个链表没有交点,返回 null

示例

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

解析

使用双指针的方式

情况一:两个链表相交

链表headA 和headB 的长度分别是 mm 和 nn。假设链表 headA 的不相交部分有 aa 个节点,链表 headB 的不相交部分有 bb 个节点,两个链表相交的部分有 cc 个节点,则有 a+c=m,b+c=n。

如果 a=b,则两个指针会同时到达两个链表相交的节点,此时返回相交的节点;

如果 a 不等于b,则指针 pA 会遍历完链表 headA,指针 pB 会遍历完链表headB,两个指针不会同时到达链表的尾节点,然后指针 pA 移到链表 headB 的头节点,指针 pB 移到链表headA 的头节点,然后两个指针继续移动,在指针 pA 移动了 a+c=c+b 次、指针pB 移动了 b+c = c+a 次之后,两个指针会同时到达两个链表相交的节点,该节点也是两个指针第一次同时指向的节点,此时返回相交的节点。

情况二:两个链表不相交

链表headA 和 headB 的长度分别是 mm 和 nn。考虑当 m=n 和 m 不等于 n 时,两个指针分别会如何移动:

如果 m=n,则两个指针会同时到达两个链表的尾节点,然后同时变成空值null,此时返回null;

如果 m 不等于n,则由于两个链表没有公共节点,两个指针也不会同时到达两个链表的尾节点

leetcode-cn.com/problems/in…

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

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
    let a = headA;
  let b = headB;
  if (!a || !b) return null;
  while (a !== b) {
    // 这里非常非常巧妙,分为相交和不相交两种情况
    a = a == null ? headB : a.next;
    b = b == null ? headA : b.next;
  }
  return a;
};

141. 环形链表

leetcode-cn.com/problems/li…

题目描述

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

示例

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

解析

使用快慢指针的方式去解决这个问题

慢指针走一步,快指针走两步,那么假如有环的话,慢指针会等于快指针

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

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    let slow = head;
    let fast = head;

    while (slow && fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
        if (slow == fast) return true;
    }
    return false;
};

25. K 个一组翻转链表

leetcode-cn.com/problems/re…

描述

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

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

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

进阶:

你可以设计一个只使用常数额外空间的算法来解决此问题吗? 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

demo

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

解析

这个题目用到了递归和链表的反转

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var reverseLists = function (head, end) {
    // end 节点 用于终止reverse
    let current = head;
    let prev = head;

    while (current != end) {
        let tmp = current.next;
        current.next = prev;
        prev = current;
        current = tmp;
    }
    return prev;

};
var reverseKGroup = function(head, k) {
    let left = head; 
    let right = head;

    for (let i= 0; i < k; i++) {
        // 这里的意思是,如果不到k个链表就没有了,说明就不反转了
        if (right == null) return head;
        right = right.next;
    }
    // 此时,left是头节点,right是一组的尾节点

    let newHead = reverseLists(left, right);
    // 这里是转换之后的
    left.next = reverseKGroup(right, k);
    return newHead;
};