[路飞_js算法:删除中间节点 两数相加 II 重排链表 移除无效的括号 复杂链表的复制]

170 阅读3分钟

删除中间节点

问题描述: 若链表中的某个节点,既不是链表头节点,也不是链表尾节点,则称其为该链表的「中间节点」。

假定已知链表的某一个中间节点,请实现一种算法,将该节点从链表中删除。(by leetcode 02.03)

例如,传入节点 c(位于单向链表 a->b->c->d->e->f 中),将其删除后,剩余链表为 a->b->d->e->f

示例:

输入:节点 5 (位于单向链表 4->5->1->9 中)
输出:不返回任何数据,从链表中删除传入的节点 5,使链表变为 4->1->9

思路: 用当前点冒充下一个点,删除下一个点。

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} node
 * @return {void} Do not return anything, modify node in-place instead.
 */
var deleteNode = function(node) {
   node.val=node.next.val;
  node.next=node.next.next;
    
};

两数相加 II

问题描述: 给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。(by lkeetcode 445

示例1:

img

输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]

思路: 利用栈的数据结构,把链表分别压入两个栈中,求和压入新的栈中,求和注意记录上一次求和是否需要进位。最后把栈转成链表。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function(l1, l2) {
     let stack1=[],stack2=[];
    while(l1){
        stack1.push(l1.val);
        l1=l1.next
    }
    while(l2){
        stack2.push(l2.val);
        l2=l2.next
    }
    let temp=0;
    let ans=null;
    while(stack1.length||stack2.length||temp==1){
        if(!stack1.length){
            stack1.push(0)
        }
        if(!stack2.length){
            stack2.push(0)
        }
        let ele=stack1[stack1.length-1]+stack2[stack2.length-1]+temp;
        if(ele>9){
            ele=ele-10;
            temp=1;
        }else{
             temp=0;
        }
        stack1.pop()
        stack2.pop()
        let newhead=new ListNode(ele);
        newhead.next=ans;
        ans=newhead;
    }
    
    return ans
};

重排链表

问题描述: 给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。(by leetcode 143)

示例 :

img

输入:head = [1,2,3,4]
输出:[1,4,2,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 {void} Do not return anything, modify head in-place instead.
 */
var reorderList = function(head) {
 if(head==null)return
     let stack=[];
     while(head!=null){
         stack.push(head);
         head=head.next
     }
    let i=0,j=stack.length-1;
   while(i<j){
    stack[i].next=stack[j];
    i++;
    if(i==j)break;
    stack[j].next=stack[i];
    j--
   }
   stack[i].next=null;
};

//优化版本
//反转链表
 function reverse(head){
    if(head==null||head.next==null){return head}
    let pre=null,cur=head;
    while(cur){
        let next=cur.next;
        cur.next=pre;
        pre=cur;
        cur=next;
    }
    return pre;
}
var reorderList = function(head) {
 //  找到中间节点,将链表一分为二(用快慢指针)
    let slow=head,fast=head;
    while(fast.next!==null&&fast.next.next!==null){
        slow=slow.next;fast=fast.next.next;
    }
    fast=slow.next;
    slow.next=null;
    // 后段链表反转
    fast=reverse(fast);
    // 两条链表拼接
    while(head!==null&&fast!==null){
        let headn=head.next;
        let fastn=fast.next;
        head.next=fast;
        fast.next=headn;
        head=headn;
        fast=fastn
    }
};

移除无效的括号

问题描述: 给你一个由 '('')' 和小写字母组成的字符串 s

你需要从字符串中删除最少数目的 '(' 或者 ')' (可以删除任意位置的括号),使得剩下的「括号字符串」有效。

请返回任意一个合法字符串。(by leetcode 1249

有效「括号字符串」应当符合以下 任意一条 要求:

  • 空字符串或只包含小写字母的字符串

  • 可以被写作 ABA 连接 B)的字符串,其中 AB 都是有效「括号字符串」

  • 可以被写作 (A) 的字符串,其中 A 是一个有效的「括号字符串」

示例 :

输入:s = "lee(t(c)o)de)"
输出:"lee(t(c)o)de"
解释:"lee(t(co)de)" , "lee(t(c)ode)" 也是一个可行答案。

思路: 采用计数的方式 先把多余的右括号去掉,然后从后往前看,多余的左括号先删除(因为左括号是在左边,所以从右开始,避免返回的无效)

/**
 * @param {string} s
 * @return {string}
 */
var minRemoveToMakeValid = function(s) {
     s=s.split("");
     let str=[],count=0;
     for(let i=0,len=s.length;i<len;i++){
       if(s[i]=="("){count++;str.push(s[i])}
       else if(s[i]==")"){
             count--;
         if(count<0){count=0;}
         else{str.push(s[i])}
       }
       else{
          str.push(s[i])
       }
     }
     let i=str.length-1
     while(count>0){
         if(str[i]=="("){
             count--;
             str.splice(i,1,"");
         }
         i--;

     }
     return str.join("")
};

复杂链表的复制

问题描述: 请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。(by leetcode 35)

示例 :

img

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

思路:

/**
 * // Definition for a Node.
 * function Node(val, next, random) {
 *    this.val = val;
 *    this.next = next;
 *    this.random = random;
 * };
 */

/**
 * @param {Node} head
 * @return {Node}
 */
var copyRandomList = function(head) {
    if (head === null) {
        return head;
    }
    let p=head;
    while(p){
        const nodeNew = new Node(p.val, p.next, null);
        p.next = nodeNew;
        p=nodeNew.next;
    }
    p=head;
    while(p){
        const nodeNew = p.next;
        nodeNew.random = (p.random !== null) ? p.random.next : null;
        p=nodeNew.next;
    }
    p=head;
     let headNew=head.next
    while(p){
        let node=p.next;
        p.next=node.next;
        node.next = (node.next !== null) ? node.next.next : null;
        p=p.next;
    }
    return headNew;
};