剑指 Offer 30. 包含min函数的栈 剑指 Offer 35. 复杂链表的复制

剑指 Offer 30. 包含min函数的栈

class MinStack {
     Stack<Integer> stack;
    /** initialize your data structure here. */
    public MinStack() {
        stack=new Stack<>();

    }
    
    public void push(int x) {
        stack.push(x);

    }
    
    public void pop() {
        stack.pop();

    }
    
    public int top() {
        return stack.peek();

    }
    
    public int min() {
        int min=stack.peek();
        for(int num:stack){
            if(num<min){
                min=num;
            }
        }
        return min;
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.min();
 */

方法二:
用空间换时间的辅助栈解法

//普通栈的 push() 和 pop() 函数的复杂度为 O(1) ;而获取栈最小值 min() 函数需要遍历整个栈,复杂度为 O(N) 。
//本题难点: 将 min() 函数复杂度降为 O(1) ,可通过建立辅助栈实现;

//注:
//Java 代码中,由于 Stack 中存储的是 int 的包装类 Integer ,因此需要使用 equals() 代替 == 来比较值是否相等。
class MinStack {
    Stack<Integer> stack1;
    Stack<Integer> stack2;
    /** initialize your data structure here. */
    public MinStack() {
        stack1=new Stack<>();
        stack2=new Stack<>();

    }
    
    public void push(int x) {
        stack1.push(x);
        if(stack2.isEmpty() || stack2.peek()>=x){
            stack2.push(x);
        }

    }
    
    public void pop() {
        //Java 代码中,由于 Stack 中存储的是 int 的包装类 Integer ,因此需要使用 equals() 代替 == 来比较值是否相等。
        if(stack2.peek().equals(stack1.pop())){
            stack2.pop();
        }

    }
    
    public int top() {
        return stack1.peek();

    }
    
    public int min() {
        return stack2.peek();

    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.min();
 */

剑指 Offer 35. 复杂链表的复制

此题不理解链表的复制过程,没有意识到复制的难点在于random节点如何去复制。(思想误区:并不是直接将节点复制给节点就完成了复制)

正常情况下的复制:

class Solution {
    public Node copyRandomList(Node head) {
        Node cur = head;
        Node dum = new Node(0), pre = dum;
        while(cur != null) {
            Node node = new Node(cur.val); // 复制节点 cur
            pre.next = node;               // 新链表的 前驱节点 -> 当前节点
            // pre.random = "???";         // 新链表的 「 前驱节点 -> 当前节点 」 无法确定
            cur = cur.next;                // 遍历下一节点
            pre = node;                    // 保存当前新节点
        }
        return dum.next;
    }
}

最终做法:

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
        if(head==null) return head;
        //思路:利用哈希表的查询特点,考虑构建 原链表节点和新链表对应节点的键值对映射关系,再遍历构建新链表各节点的 next 和 random引用指向
    Map<Node,Node> map=new HashMap<>();
    Node cur=head;
    while(cur!=null){
        map.put(cur,new Node(cur.val));
        cur=cur.next;
    }
    cur=head;
    while(cur!=null){
        map.get(cur).next=map.get(cur.next);
        map.get(cur).random=map.get(cur.random);
        cur=cur.next;
    }
    //最后返回哈希表的新头结点即可
    return map.get(head);
    }
}

拼接 + 拆分法

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
        //拼接法,第一步,新链表的拼接不会
        if(head==null) return head;
        Node cur=head;
        while(cur!=null){
            Node temp=new Node(cur.val);
            temp.next=cur.next;
            cur.next=temp;
            cur=temp.next;
        }
        cur=head;
        while(cur!=null){
            if(cur.random!=null){
                //要理解这一步随机指向的实现
                cur.next.random=cur.random.next;
            }
            cur=cur.next.next;
        }
        //第三步:联编拆分为两个链表,操作不熟
        cur=head.next;
        Node l1=head;
        Node l2=head.next;
        //注意一下节点移动两次时遍历过程条件的特点
        while(cur!=null&&cur.next!=null){
            l1.next=l1.next.next;
            cur.next=cur.next.next;
            l1=l1.next;
            cur=cur.next;
        }
        //注意原来的链表最后一个节点指向null
        l1.next=null;
        return l2;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值