小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
算法是程序员绕不开的话题,而链表又是算法中首当其冲的部分,为了一举拿下链表知识,今天是链表专题的简单系列~
1. 反转链表
题目:
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
解析:
一共三个指针,pre,cur,next,循环链表时指针依次向前走一步,循环的截止条件:cur指针在最后一个节点时做最后一次循环,即cur为null时不再循环
var reverseList = function(head) {
let pre = null
let cur = head
while(cur) {
let next = cur.next
cur.next = pre
pre = cur
cur = next
}
return pre
};
时间复杂度: O(n),因为要循环整个链表
空间复杂度: O(1),因为只新建了三个指针占用存储
2. 合并两个有序链表
题目:
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
解析
新建一个头指针pos,循环两个链表,两个链表的当前节点分别为l1、l2,pos.next指向l1、l2中较小的节点,循环截止条件:当l1.next === null 或者 l2.next === null时。
var mergeTwoLists = function(l1, l2) {
let pos = new ListNode(1, 1)
let cur = pos
while(l1 && l2) {
if(l1.val < l2.val) {
cur.next = l1
cur = l1
l1 = l1.next
}else {
cur.next = l2
cur = l2
l2 = l2.next
}
}
l1 === null ? cur.next = l2 : cur.next = l1
return pos.next
};
时间复杂度: O(n),因为每次循环只取l1或者l2中的一个节点,所以循环的次数为O(m+n)
空间复杂度: O(1),因为只新建了一个指针占用存储
3. 回文链表
题目:
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。其实就是判断链表是否对称
解析:
- 用快慢指针找到中间节点,当快指针为null时,慢指针在中间节点,节点个数为奇数和偶数时的情况如下:
2.把slow指针后面的部分反转(用到第一题的解法)
3.反转后,遍历前后两部分head1、head2,节点值一直相同,则是回文链表。循环截止条件:head2为null时,不再遍历
4.如有需要则再恢复链表
var isPalindrome = function(head) {
// 快慢指针找出中间节点
let slow = head
let fast = head
while(fast.next && fast.next.next) {
slow = slow.next
fast = fast.next.next
}
// 反转后半部分
let pre = null
let cur = slow.next
while(cur) {
let next = cur.next
cur.next = pre
pre = cur
cur = next
}
let head1 = head
let head2 = pre
// 比较得出结果
while(head2) {
if(head1.val === head2.val) {
head1 = head1.next
head2 = head2.next
} else {
return false
}
}
return true
};
时间复杂度: O(n),快慢指针部分O(n/2),反转链表部分O(n/2),比较部分O(n/2)
空间复杂度: O(1),因为新建指针个数也是常数量级
4. 环形链表
题目
给定一个链表,判断链表中是否有环。
解析
方法1:标记节点
判断链表中是否有环,可以通过判断节点是否被访问第二次,如果节点被第二次访问,则存在环。所以我们给访问过的节点加上标记。
var hasCycle = function(head) {
while(head) {
if(head.flag) {
return true
} else {
head.flag = true
head = head.next
}
}
return false
};
时间复杂度: O(n),因为要循环整个链表
空间复杂度: O(n),因为在每个节点都开辟了新的空间存储flag
方法2:快慢指针
快慢指针法,如果有环,快慢指针就一定会相遇,就想环形跑道,速度慢的人一定会和速度快的在某个地方相遇。
var hasCycle = function(head) {
if(!head) return false
let slow = head
let fast = head
while(fast && fast.next) {
slow = slow.next
fast = fast.next.next
if(slow === fast) {
return true
}
}
return false
};
时间复杂度: O(n),因为要循环整个链表
空间复杂度: O(1),因为新建指针个数也是常数量级
以上就是链表系列的简单部分,后续会持续更新~
原创文章,希望对你有帮助,也为社区贡献自己的一份力量!喜欢请点赞哦~
作者:前端小小梦
主页:了解更多,点击个人主页