前言
本篇博客主要是在leetcode上做算法题的一些思路,前段时间一直没时间整理,今天整理了在这里记录一下。
反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2] 输出:[2,1]
示例 3:
输入:head = [] 输出:[]
提示:
链表中节点的数目范围是 [0, 5000] -5000 <= Node.val <= 5000
思路:
- 迭代:使用三个标志,分别记录当前节点
cur ,当前节点的前一个节点pre 和下一个节点tem ,先记录下一个节点pre = cur.next 然后让当前节点的指针指向前一个节点cur.next = pre ;再将标志向后移一个位置:cur = tem,pre = cur; 直到cur = null; 循环结束。 - 递归:递归的思路是一样的,只是在写法上略有不同。
迭代
var reverseList = function(head) {
var pre = null, cur = head;
while (cur != null) {
var tem = cur.next;
cur.next = pre;
pre = cur;
cur = tem;
}
return pre;
};
递归
var reverseList = function(head) {
var pre = null, cur = head;
return fn(pre, cur);
};
var fn = function(pre, cur) {
if (cur == null) return pre;
var tem = cur.next;
cur.next = pre;
pre = cur;
return fn(pre, tem);
}
问题:为什么pre 初始化为null ?
因为链表反转后第一个节点变为最后一个节点,所以它的next 指针应当为null ,并且在改变cur 的next 指针时cur.next = pre; 第一个节点指针最终会指向pre ,所以pre 初始化为null 符合代码逻辑。
环形链表
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:返回索引为 0 的链表节点 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:返回 null 解释:链表中没有环。
提示:
链表中节点的数目范围在范围 [0, 104] 内 -105 <= Node.val <= 105 pos 的值为 -1 或者链表中的一个有效索引
思路:
分两步:第一步先判断有没有环;使用快慢指针,快指针每次走两步,慢指针每次走一步,如果有环,那么一定会相遇。第二步:找相交的节点;快慢指针相遇后,将慢指针初始化为head,然后他们一起走每次一步,再次相遇的结点就是环的第一个节点。
问题:为什么有环一定会相遇呢?
因为快指针每次走两步,慢指针每次走一步,快指针相对于慢指针来说在一步一步的追慢指针,所以如果有换的话一定会相遇。
问题:若有环如何计算环的入口呢?
这个问题可以看看代码随想录,那里讲得很好,可以去看看。
var detectCycle = function(head) {
if(!head || !head.next) return null;
var fast = head.next.next;
var slow = head.next;
var f = false;
while (fast && fast.next) {
if (slow == fast) {
f = true;
break;
}
fast = fast.next.next;
slow = slow.next;
}
if (!f) return null;
slow = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
};
链表相交
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入: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 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 输出:Intersected at ‘2’ 解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。 在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 输出:null 解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。 由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 这两个链表不相交,因此返回 null 。
提示:
listA 中节点数目为 m listB 中节点数目为 n 0 <= m, n <= 3 * 104 1 <= Node.val <= 105 0 <= skipA <= m 0 <= skipB <= n 如果 listA 和 listB 没有交点,intersectVal 为 0 如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]
思路:
先统计链表A的长度,再统计链表B的长度,计算出他们的长度差sub,然后让快指针指向更长的链表,并让他先走sub步,然后快慢指针一起走,则他们相等的节点一定就是他们的交点。
var getIntersectionNode = function(headA, headB) {
var fast = headA, slow = headB;
var num1 = num2 = 0;
while (fast != null) {
num1++;
fast = fast.next;
}
while (slow != null) {
num2++;
slow = slow.next;
}
var sub = Math.abs(num1 - num2);
if (num1 > num2) {
fast = headA;
slow = headB;
} else {
fast = headB;
slow = headA;
}
while (sub--) {
fast = fast.next;
}
while (fast != null) {
if (fast == slow) {
return fast;
} else {
fast = fast.next;
slow = slow.next;
}
}
return null;
};
|