LeetCode 24. 两两交换链表中的节点
题目描述:
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,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) {
let node=new ListNode(0,null);
node.next=head;
pre=node;
let cur=head;
while(cur!=null&&cur.next!=null)
{
pre.next=cur.next;
cur.next=pre.next.next;
pre.next.next=cur
cur=cur.next;
pre=pre.next.next;
}
return node.next;
};
LeetCode 19. 删除链表的倒数第 N 个结点
题目描述:
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
解题思路
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mik1u9eT-1673861460221)
第一种写法(本人写法,先计算总数,后减去倒数的就是正数的了)
/**
* 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} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
let cur=head;
let count=0;
while(cur!=null)
{ count++;
cur=cur.next;
}
if (count === n) {
head = head.next;
} else {
cur=head;
for (let i = 0; i < count - n - 1; i++) {
cur = cur.next;
}
cur.next=cur.next.next;}
return head;
};
第二种写法(双指针)
/**
* 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} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
let res =new ListNode(0,head);
let p=res;
let slow=p.next;
let fast=p.next;
let count=1;
for(let i=0;i<n;i++)
{
fast=fast.next;
count++;
}
if(fast==null)
{
p.next=slow.next;
return res.next
}
while(fast.next!=null)
{
count++;
slow=slow.next;
fast=fast.next;
p=p.next;
}
if(fast.next==null)
{
slow.next=slow.next.next;
}
return res.next;
};
面试题 02.07. 链表相交
题目描述:
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
图示两个链表在节点 c1
开始相交**:**
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 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 个节点。
解题思路
代码可以写的非常简洁漂亮
求长度方法可以分离出去,减少代码的耦合
var getListLen = function(head) {
let len = 0, cur = head;
while(cur) {
len++;
cur = cur.next;
}
return len;
}
在解决题目中,不论链表A长还是链表B长,都转换为A长,统一解决问题,不然代码冗长
[curA,curB]=[curB,curA];
[len1,len2]=[len2,len1];
写法
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getListLen = function(head) {
let len = 0, cur = head;
while(cur) {
len++;
cur = cur.next;
}
return len;
}
var getIntersectionNode = function(headA, headB) {
let curA=headA; let curB=headB;
let len1=getListLen(headA);
let len2=getListLen(headB);
if(len1<len2)
{
[curA,curB]=[curB,curA];
[len1,len2]=[len2,len1];
}
let i=len1-len2;
while(i-->0)
{
curA=curA.next;
}
while(curA!=null&& curA!=curB)
{
curA=curA.next;
curB=curB.next;
}
return curA;
};
反思:
这个题目每次我写代码都非常冗长,因为没有将一些方法分离出去,也未考虑可以统一使用认定a长来解决额外问题,使得重复的代码非常多。
LeetCode 142. 环形链表 II
题目描述:
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。xxxxxxxxxx 输入:head = [3,2,0,-4], pos = 1输出:返回索引为 1 的链表节点解释:链表中有一个环,其尾部连接到第二个节点。输入:head = [1,2,3,4]输出:[2,1,4,3]
解题思路
双指针之快慢指针:直观地来说就是当快慢指针相遇时,让其中任一个指针指向头节点,然后让它俩以相同速度前进,再次相遇时所在的节点位置就是环开始的位置
重要问题
第一种写法
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var detectCycle = function(head) {
let fast=head;
let slow=head;
while(fast!=null&&fast.next!=null)
{
fast=fast.next.next;
slow=slow.next;
if(fast==slow) {
slow=head;
while(fast!=slow)
{
slow=slow.next;
fast=fast.next;
}
return slow;
};
}
return null;
};