剑指 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;
}
}