文章目录
1. JZ 3 从尾到头打印链表
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
//listNode 是链表,只能从头遍历到尾,但是输出却要求从尾到头,这是典型的"先进后出",我们可以想到栈!
function printListFromTailToHead(head)
{
let stack = []
let p = head
while(p){
stack.push(p.val)
p = p.next
}
let ArrayList = []
while(stack.length){
ArrayList.push(stack.pop())
}
return ArrayList
}
2. JZ 14 链表中倒数第k个结点
输入一个链表,输出该链表中倒数第k个结点。
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
//快指针先往前走k步,注意判断边界,然后快慢一起走,当快指针为null的时候,慢指针走到了倒数第k个节点
function FindKthToTail(head, k)
{
if(!head || !k || k <= 0){
return null
}
let fast = head, slow = head
for(let i = 0; i < k - 1; i++){
if(fast.next) {
fast = fast.next
} else {
return null
}
}
while(fast.next){
fast = fast.next
slow = slow.next
}
return slow
}
3. JZ 15 反转链表
输入一个链表,反转链表后,输出新链表的表头。
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
function ReverseList(pHead)
{
if (pHead == null){
return null
}
let p = pHead,
q = pHead.next
while(q){
let temp = q.next
q.next = p
p = q
q = temp
}
pHead.next = null
return p
}
4. JZ 16 合并两个排序的链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
function Merge(pHead1, pHead2)
{
let res = null
//既是特殊情况排除
//也是结束递归的条件,如果其中一个链表循环完了,直接把另一链表放入res
if(pHead1 == null){
return pHead2
}
if(pHead2 == null){
return pHead1
}
if(pHead1.val < pHead2.val){
res = pHead1
res.next = Merge(pHead1.next, pHead2)
}else{
res = pHead2
res.next = Merge(pHead1, pHead2.next)
}
return res
}
5. JZ 25 复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
/*function RandomListNode(x){
this.label = x;
this.next = null;
this.random = null;
}*/
//用一个哈希表表示映射关系:键是原节点,值是复制的节点
function Clone(pHead)
{
if(!pHead){return pHead}
let map = new Map() //Map对象初始化
//首先确定复制链表的头节点
let newpHead = new RandomListNode(pHead.label)
//从头节点就开始保存映射关系
let node = pHead
let newNode = newpHead
map.set(node, newNode)
//第一次遍历,复制每个节点和 next 指针,并且保存“原节点-复制节点”的映射关系
while(node.next){
newNode.next = new RandomListNode(node.next.label)
node = node.next
newNode = newNode.next
map.set(node, newNode)
}
//第二次遍历,复制 random 指针
node = pHead //先还原指针位置
newNode = newpHead
while(newNode.next){
newNode.random = map.get(node.random)
node = node.next
newNode = newNode.next
}
return newpHead
}
6. JZ 26 二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
/* function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
} */
//1.中序遍历二叉树,用一个数组储存 2.为每个节点赋予双向关系
var midorderRes = [] //储存中序遍历结果
function Convert(pRootOfTree)
{
if(pRootOfTree == null){
return null
}
if(pRootOfTree.left == null && pRootOfTree.right == null){
return pRootOfTree
}
Midorder(pRootOfTree) //先中序遍历
let head = midorderRes.shift() //双向连报表的头节点
let pre = head //pre指针,首先指向头节点
let cur //声明cur指针
while(midorderRes.length){
cur = midorderRes.shift() //cur指针指向了pre指针的下一个
cur.left = pre //建立两指针的对应关系
pre.right = cur
pre = cur
}
head.left = null //头节点的left指向空,否则就变成了循环链表。但不加也可以通过
cur.right = null //尾节点的right指向空。不加也可以
return head
}
function Midorder (pHead){ //递归中序遍历。注意理解!
if(pHead == null) return
Midorder(pHead.left)
midorderRes.push(pHead)
Midorder(pHead.right)
}
7. JZ 36 两个链表的第一个公共结点
输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
function FindFirstCommonNode(pHead1, pHead2)
{
if(pHead1 == null||pHead2 == null){
return null
}
let p1 = pHead1;
let p2 = pHead2;
while(p1 != p2){
p1 = p1.next;
p2 = p2.next;
if(p1 != p2){
if (p1 == null){
p1 = pHead2
}
if (p2 == null){
p2 = pHead1
}
}
}
return p2
}
8. JZ 55 链表中环的入口结点
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
function EntryNodeOfLoop(pHead)
{
if(!pHead||!pHead.next||!pHead.next.next){
return null
}
//快慢指针先到相遇点
let fast = pHead.next.next
let slow = pHead.next
while(fast&&slow){
if(fast!==slow){
fast=fast.next.next
slow=slow.next
}else{
break
}
}
//相同速度指针,一个从头节点走,一个从相遇的地方走
let p = pHead
let q = fast
while(p!==q){
p = p.next
q = q.next
}
return p
}
9. JZ 56 删除链表中重复的结点
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
function deleteDuplication(pHead)
{
if (pHead == null || pHead.next == null){
return pHead
}
let newHead = new ListNode(1) //建立一个辅助头节点
newHead.next = pHead //辅助头节点连接真正头节点,便于cur指针从真正头节点开始
let pre = newHead //pre指针为辅助头节点
let cur = pHead //cur指针需从表头开始
while(cur){
if(cur.next && cur.val == cur.next.val){
//一旦存在重复,就找重复到哪里
while(cur.next && cur.val == cur.next.val){
cur = cur.next
}
cur = cur.next
pre.next = cur
}else{
pre = cur
cur = cur.next
}
}
return newHead.next //最后返回时要去掉辅助头节点
}