JZ 链表有关

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  //最后返回时要去掉辅助头节点
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值