剑指 Offer 09. 用两个栈实现队列
题目:
用两个栈实现一个队列,请实现它的两个函数 appendTail
和 deleteHead
,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead
操作返回 -1 )
思路:
- 初始化两个栈
stack1
和stack2
,stack2
用来维护所需删除的元素; -
appendTail
函数的实现直接在栈尾部push元素即可; -
deleteHead
删除头部元素,用stack2
来存储stack1
的反向栈,删除stack2
的栈顶元素即是stack1
的队尾元素。
class CQueue {
Stack<Integer> stack1;
Stack<Integer> stack2;
public CQueue() {
stack1 = new Stack<Integer>();
stack2 = new Stack<Integer>();
}
public void appendTail(int value) {
stack1.push(value);
}
public int deleteHead() {
if (stack2.isEmpty()) {
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}//若stack2为空,则将stack1中的反转
}
if (stack2.isEmpty()) {
return -1;
} else {
int deleteItem = stack2.pop();
return deleteItem;
}
}
}
剑指 Offer 30. 包含min函数的栈
题目:
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
思路:
min()
函数对当前的栈进行遍历,每次均更新min
值即可
class MinStack {
private Stack<Integer> stack;
private int min = Integer.MAX_VALUE;
public MinStack() {
stack = new Stack<Integer>();
}
public void push(int x) {
stack.push(x);
}
public void pop() {
stack.pop();
}
public int top() {
return stack.peek();
}
public int min() {
min = Integer.MAX_VALUE;
for ( Integer x:stack){
min=Math.min(x,min);
}
return min;
}
}
剑指 Offer 06. 从尾到头打印链表
题目:
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)
思路1:
读取链表数据存储在list
中,list翻转,转存入数组中
public int[] reversePrint(ListNode head) {
List<Integer> list = new ArrayList<>();
while (head!=null){
list.add(head.val);
head=head.next;
}
Collections.reverse(list);
int[] a = new int[list.size()];
for (int i=0;i<list.size();i++){
a[i]=list.get(i);
}
return a;
}
剑指 Offer 24. 反转链表
题目:
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
思路:
将每个节点Listnode
压入栈中,压栈结束之后不断的弹栈生成新的反转链表
public ListNode reverseList(ListNode head) {
Stack<ListNode> stack = new Stack<>();
//压栈
while (head!=null){
stack.push(head);
head = head.next;
}
ListNode res = new ListNode(0);//创建头节点
ListNode temp = res;
while (!stack.isEmpty()){//弹栈创建新的链表
ListNode node = new ListNode(stack.pop().val);
temp.next= node;
temp=temp.next;
}
return res.next;
}
剑指 Offer 35. 复杂链表的复制
题目:
请实现 copyRandomList
函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next
指针指向下一个节点,还有一个 random
指针指向链表中的任意节点或者 null
。
思路1(浅拷贝):
- 每个节点都有3个变量,
val
,next
,random
,三个变量分别和下标组合形成三个map
- 通过遍历链表,将数据存储在map中
- 通过循环不断地在map中取出数据形成新的链表
public Node copyRandomList(Node head) {
Map<Integer,Integer> val = new HashMap<>();
Map<Integer,Node> next = new HashMap<>();
Map<Integer,Node> random = new HashMap<>();
int i=1;
while (head!=null){
val.put(i,head.val);
next.put(i,head.next);
random.put(i,head.random);
head=head.next;
i++;
}
Node res = new Node(0);
Node temp = res;
for (int j=1;j<i;j++){
Node node = new Node(val.get(j));
node.next = next.get(j);
node.random = random.get(j);
temp.next=node;
temp = temp.next;
j++;
}
return res.next;
}
思路2(深拷贝):
- 遍历链表,通过创建新节点的方式拷贝
val
和next
两个变量 - 创建
map
来存储新旧节点之间的对应关系(因为在拷贝random
指针时,指针位置不易确定) - 先获取旧节点的
random
值,然后在map
中查找,查找结果作为新节点的random
值
public Node copyRandomList(Node head) {
Map<Node,Node> map = new HashMap<>();
Node curr = head;
Node newNode = new Node(0);
Node newCurr = newNode;
while (curr!=null){
Node node = new Node(curr.val);
map.put(curr,node);
newCurr.next = node;
newCurr = newCurr.next;
curr= curr.next;
}
curr = head;
newCurr = newNode.next;
while (curr!=null){
if (map.containsKey(curr.random)){
newCurr.random = map.get(curr.random);
}else {
newCurr.random=null;
}
newCurr = newCurr.next;
curr= curr.next;
}
return newNode.next;
}
关于浅拷贝和深拷贝
1、浅拷贝:小明不想搬砖了,于是克隆了小明的副本,但是忘记克隆一台电脑,此时小明和小明的副本共用一台电脑一起搬砖;
2、深拷贝:小明克隆了小明的副本和电脑副本,此时小明用电脑,小明的副本用电脑副本两个人一起搬砖。
3、深浅拷贝的原理以及java
实现 Java 浅拷贝和深拷贝
剑指 Offer 05. 替换空格
题目:
请实现一个函数,把字符串 s
中的每个空格替换成"%20"
。
public String replaceSpace(String s) {
return s.replace(" ","%20");
}
剑指 Offer 58 - II. 左旋转字符串
题目:
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。
比如,输入字符串"abcdefg"
和数字2
,该函数将返回左旋转两位得到的结果"cdefgab"
。
思路:
获取后半部分的字符子串再与前面的子串连接
public String reverseLeftWords(String s, int n) {
return s.substring(n).concat(s.substring(0,n));
}
十一过得真快乐
但我只感受到了前六个字