《剑指Offer:专项突破版》 - 链表部分 JavaScript 题解
Posted 前端GoGoGo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《剑指Offer:专项突破版》 - 链表部分 JavaScript 题解相关的知识,希望对你有一定的参考价值。
《剑指Offer:专项突破版》是一个算法题集。该题单包含了程序员在准备面试过程中必备的数据结构与算法知识。具体包含:
本文来分享下链表部分题的解法~
类似。可以用类似的算法来求解:反转两个链表。 将反转后的链表的每位依次相加。直到达到长的链的尾部。如果当前位已超过了短链的长度,则短链当前位的值为0。用长链来存求和的结果。 如果长链的最高位进位了,则在链的尾部添加值为1的节点。 反转长链。
代码如下:
和 [4, 5, 6]
。
[6, 5, 4]
。[1, 6, 2, 5, 3, 4]
。将链表按长度平均分成两部分,可以用快慢指针来实现。快指针一次走两步,慢指针一次走一步。快指针走到链表末尾时,慢指针指向的就是中间节点。
完整的实现代码如下:
const reorderList = function (head)
if (!head || !head.next || !head.next.next)
return head;
let prevHalf, afterHalf = divideToHalf(head);
afterHalf = reverseList(afterHalf);
while (prevHalf)
const prevHalfNext = prevHalf.next;
prevHalf.next = afterHalf;
if (afterHalf)
// 奇数到末尾的情况
const afterHalfNext = afterHalf.next;
afterHalf.next = prevHalfNext;
afterHalf = afterHalfNext;
prevHalf = prevHalfNext;
return head;
;
// 链表长度至少为3。
function divideToHalf(head)
let fast = head;
let slow = head;
let middle = head;
while (fast && fast.next)
fast = fast.next.next;
middle = slow;
slow = slow.next;
const isOdd = !!fast;
let afterHalf;
if (isOdd)
// 奇数
afterHalf = slow.next;
slow.next = null;
else
afterHalf = middle.next;
middle.next = null;
return
prevHalf: head,
afterHalf,
;
题7 - 剑指 Offer II 027. 回文链表问题:如何判断一个链表是不是回文?要求解法的时间复杂度是O(n),并且不得使用超过O(1)的辅助空间。如果一个链表是回文,那么链表的节点序列从前往后看和从后往前看是相同的。
题的力扣地址[8]
回文链表的特点是:将链表一分为二,后半部分反转后和前半部分的节点的值都相同。因此,不难设计出如下的算法:
将链表一分二。如果链表长度是奇数个,去掉中间节点。 反转后半部分链表,然后比较前后两部分是否相等。
核心代码如下:
const isPalindrome = (head) =>
if (!head || !head.next)
return true;
let prevHalf, afterHalf = divideToHalf(head);
afterHalf = reverseList(afterHalf);
while (prevHalf)
if (prevHalf.val !== afterHalf.val)
return false;
prevHalf = prevHalf.next;
afterHalf = afterHalf.next;
return true;
;
题8 - 剑指 Offer II 028. 展平多级双向链表问题:在一个多级双向链表中,节点除了有两个指针分别指向前后两个节点,还有一个指针指向它的子链表,并且子链表也是一个双向链表,它的节点也有指向子链表的指针。请将这样的多级双向链表展平成普通的双向链表,即所有节点都没有子链表。
题的力扣地址[9]
这题看起来很难,其实用递归的方式来做很容易。算法如下:
遍历链表,遇到有子链表的,把该节点的下一个节点丢入栈中。 递归调用,将 子链表展平 后的节点,设置为父节点的下一个节点。 遍历完链表,取出栈中的节点。递归调用,将 节点展平 后的节点,添加到链表的末尾。 重复上一步,值到栈为空。程序结束。
代码如下:
const flatten = function (head)
if (!head)
return head;
const stack = [];
let currNode = head;
let lastNode = null;
while (currNode)
if (currNode.child)
stack.push(currNode.next);
currNode.next = flatten(currNode.child);
currNode.child.prev = currNode;
currNode.child = null;
lastNode = currNode;
currNode = currNode.next;
while (stack.length)
const node = stack.pop();
if (node)
lastNode.next = flatten(node);
node.prev = lastNode;
return head;
;
题9 - 剑指 Offer II 029. 排序的循环链表问题:在一个循环链表中节点的值递增排序,请设计一个算法在该循环链表中插入节点,并保证插入节点之后的循环链表仍然是排序的。
题的力扣地址[10]
算法如下:
遍历一圈,找到环中值最大的节点,最大值和最小值。 如果插入值大于等于最大值或小于等于最小值。则该节点插入到最大值和最小值节点中间。 插入值处于最大值,最小值中间时,从最小节点开始遍历,找到要插入的节点。
该题包含的情况挺多的,要注意下。比如:
完整代码如下:
const insert = function (head, insertVal)
const insertNode = new Node(insertVal);
// 没有节点的情况
if (!head)
insertNode.next = insertNode;
return insertNode;
// 一个节点的情况
if (head.next === head)
insertNode.next = head;
head.next = insertNode;
return head;
// 两个节点的情况
if (head.next.next === head)
if (insertVal > head.next.val || insertVal < head.val)
insertNode.next = head;
head.next.next = insertNode;
else
let temp = head.next;
head.next = insertNode;
insertNode.next = temp;
return head;
let max = Number.MIN_VALUE;
let min = Number.MAX_VALUE;
const firstNode = head;
let beforeNode = firstNode;
let currNode = beforeNode.next;
let nextNode = currNode.next;
let maxNode;
let beforeMaxNode;
// 找最大值和最小值
while (currNode.next !== firstNode.next)
const currMax = Math.max(currNode.val, nextNode.val);
const currMin = Math.min(currNode.val, nextNode.val);
// 可能会存在多个最大值相同的情况。不加等号会出问题。
if (currMax >= max)
max = currMax;
beforeMaxNode = currNode.val >= nextNode.val ? beforeNode : currNode;
maxNode = beforeMaxNode.next;
if (currMin < min)
min = currMin;
beforeNode = beforeNode.next;
currNode = currNode.next;
nextNode = nextNode.next;
// 插入值大于等于最大值或小于等于最小值。则该节点插入到最大值和最小值节点中间。
const isTooBigOrSmall = insertVal >= max || insertVal <= min;
if (isTooBigOrSmall)
const beforeInsertNode = maxNode;
insertNode.next = beforeInsertNode.next;
beforeInsertNode.next = insertNode;
return head;
// 从最小节点转一圈,一定找得到插入的点
currNode = maxNode.next;
nextNode = currNode.next;
while (currNode.next !== maxNode.next)
if (currNode.val <= insertVal && nextNode.val >= insertVal)
currNode.next = insertNode;
insertNode.next = nextNode;
return head;
currNode = currNode.next;
nextNode = nextNode.next;
;
总结链表中经常会用到快慢指针的算法。可以用快慢指针的算法:
题的力扣地址: https://leetcode-cn.com/problems/SLwz0R/
[2]题的力扣地址: https://leetcode-cn.com/problems/c32eOV/
[3]题的力扣地址: https://leetcode-cn.com/problems/3u1WK4/
[4]题的力扣地址: https://leetcode-cn.com/problems/UHnkqh/
[5]题的力扣地址: https://leetcode-cn.com/problems/lMSNwu/
[6]剑指 Offer II 002. 二进制加法: https://leetcode-cn.com/problems/JFETK5/
[7]题的力扣地址: https://leetcode-cn.com/problems/LGjMqU/
[8]题的力扣地址: https://leetcode-cn.com/problems/aMhZSa/
[9]题的力扣地址: https://leetcode-cn.com/problems/Qv1Da2/
[10]题的力扣地址: https://leetcode-cn.com/problems/4ueAj6/
《剑指Offer:专项突破版》 - 哈希表部分 JavaScript 题解
《剑指Offer:专项突破版》是一个算法题集。该题单包含了程序员在准备面试过程中必备的数据结构与算法知识。具体包含:
本文来分享下哈希表部分题的解法~
和 最大值做比较,比如:["00: 00", "23:49", "23:59"]
的最小时间差不是 10 分钟(23:59 - 23:49
),而是 1 分钟(00: 00 + 24:00 - 23:59
)。代码如下:
const ONE_DAY_MINUTE = 24 * 60
const findMinDifference = function(timePoints)
if(timePoints.length <= 1)
return 0;
const minutes = timePoints.map(time => toMinute(time));
minutes.sort((a, b) => a - b);
const diff = minutes.map((m, i) =>
if(i === 0) // 最后一个和第一个的差值。
return m + ONE_DAY_MINUTE - minutes[minutes.length - 1];
return m - minutes[i - 1];
)
const min = Math.min(...diff);
return min;
;
function toMinute(time)
const [hour, minute] = time.split(\':\').map(Number);
return hour * 60 + minute;
相关阅读题的力扣地址: https://leetcode-cn.com/problems/FortPu/
[2]题的力扣地址: https://leetcode-cn.com/problems/OrIXps/
[3]题的力扣地址: https://leetcode-cn.com/problems/dKk3P7/
[4]题的力扣地址: https://leetcode-cn.com/problems/sfvd7V/
[5]题的力扣地址: https://leetcode-cn.com/problems/lwyVBB/
[6]题的力扣地址: https://leetcode-cn.com/problems/569nqc/
以上是关于《剑指Offer:专项突破版》 - 链表部分 JavaScript 题解的主要内容,如果未能解决你的问题,请参考以下文章
《剑指Offer:专项突破版》 - 哈希表部分 JavaScript 题解
《剑指Offer:专项突破版》 - 整数部分 JavaScript 题解