本文已参与「新人创作礼」活动,一起开启掘金创作之路。
单链表和双链表如何反转
单链表和双链表的反转是经典的算法题目了,在这道题目里面,我们需要创建一个pre表示前一个元素,cur表示当前元素,next表示下一个元素,
那我们循环的内容就是,cur元素的指针指向pre元素,然后把next的值给cur,cur的值给pre,这样就可以做到不丢元素的情况下反转链表。
next的存在是防止丢掉cur指向pre元素后cur后面的元素。
结束标志是next为空的时候。
public static Node reverseLinkedList(Node head){
if(head == null || head.next == null){
return head;
}
Node cur = head;
Node next = head.next;
Node pre = null;
while(next != null){
cur.next = pre;
pre = cur;
cur = next;
next = next.next;
}
cur.next = pre;
return cur;
}
上面的这个是单链表的元素
public static DoubleNode reverseDoubleList(DoubleNode head) {
DoubleNode pre = null;
DoubleNode next = null;
while (head != null) {
next = head.next;
head.next = pre;
head.last = next;
pre = head;
head = next;
}
return pre;
}
上面的这个是双链表的元素。
代码
那我们先写单链表的反转
if(head == null || head.next == null){
return head;
}
Node cur = head;
Node next = head.next;
Node pre = null;
while(next != null){
cur.next = pre;
pre = cur;
cur = next;
next = next.next;
}
cur.next = pre;
return cur;
对于双向链表怎么反转其实是一样的,只是多了一条指针需要改变,其他的都一样
DoubleNode pre = null;
DoubleNode next = null;
while (head != null) {
next = head.next;
head.next = pre;
head.last = next;
pre = head;
head = next;
}
return pre;
总结一下上面的代码,这道题是让我们不要忘记原本后面的东西,当我们看过去的眼睛看向未来的时候,也不要忘记过去带来的幸福。
把给定值删除
就是给你一条链表(head),然后再给你一个数(num),然后你要把链表里面跟这个数一样的元素删掉。 先定义一个变量cur,再定义一个变量next
现在我们来看看这两个变量怎么解决这道题目,
首先,我们让cur的值是head。next的值是cur.next,然后我们看看next是不是等于num,如果等于就next.next,如果不等于就cur.next = next;next=next.next;cur= cur.next。这个样子就可以让不等于num的数连接到链表里面, 循环的结束就是next为空的时候
这个时候我们要知道的是,最后返回的时候,我们要判断一下头是不是等于num如果等于的话要让head = head.next
代码
public static Node removeValue(Node head, int num) {
Node cur = head;
Node next = head.next;
while(next != null){
if(next.value == num){
next = next.next;
}else{
cur.next = next;
cur = next;
next = next.next;
}
}
cur.next = next;
if(head.value == num){
head = head.next;
}
return head;
}
上面的第一个循环就是让next变成一个排雷兵,让他一直向前走,看看有没有地雷,第一个if就是遇到了地雷,那有地雷了怎么办,那当然是地雷兵把雷排掉呀,那else就表示没有地雷,那这个时候cur这个指挥就可以往前走了,一步一步往前走,当循环结束的时候,next这个排雷兵完成了任务,那这个时候也要接过来,感谢一下,所以指挥的cur.next就指向了next,最后head这个头头就出来了,那在出来之前,我们还是要确认一下有没有刺杀的人,所以最后的if就是看看周围有没有刺杀的人在head的周围。
实现一个栈,在基本功能的基础上,实现返回最小元素
要求:
时间复杂度O(1)
思路:
实现这个的话,我们需要两个栈来实现,一个栈实现栈的功能,一个栈是放当前的最小值。 当第一个元素到的时候,我们把这个元素放到两个栈里,之后再来元素的时候,第一个栈可以随便放,但是第二个栈就要比较了,看看栈顶的元素和新来的元素谁小,如果是栈顶元素小的话,那么就再放一次栈顶元素,如果是新来的小的话,那就把新的放到栈顶。
代码
public static class MyStack {
private Stack<Integer> stackData;
private Stack<Integer> stackMin;
public MyStack() {
this.stackData = new Stack<Integer>();
this.stackMin = new Stack<Integer>();
}
public void push(int newNum) {
if (stackMin.isEmpty()) {
stackMin.push(newNum);
} else if (newNum < this.getmin()) {
stackMin.push(newNum);
} else {
int newMin = stackMin.peek();
stackMin.push(newMin);
}
stackData.push(newNum);
}
public int pop() {
if (stackData.isEmpty()) {
throw new RuntimeException("Your stack is empty.");
}
stackMin.pop();
return stackData.pop();
}
public int getmin() {
if (stackMin.isEmpty()) {
throw new RuntimeException("Your stack is empty.");
}
return stackMin.peek();
}
}
如何用栈实现队列
思路
这个题目的话,我们可以通过栈和队列的性质下手,
栈的性质是先进后出
队列的性质是先进先出,
我们还可以这样想,一组数,进入了栈,然后再出来的时候是顺序是逆序的,一组数,进入队列之后,然后再出来的时候顺序是不变的。
那这个时候,就有一个想法了,那我们逆置顺序之后,再逆置一遍不就可以了吗?
我们有这个想法的时候就要实践一下。我们什么时候把第一个栈放到第二个栈里面,这个时机还是很重要的。
那我告诉大家,是在弹出的时候比较重要,当我们执行弹出命令的时候,第一个数组的数字就要全部弹出到第二个数组,然后返回栈顶数组,之后再有弹出命令的时候,我们要检查第二个数组是否为空,如果为空就让第一个栈的数字再压过来,其他的时候不要来,要不然会弄乱顺序的。
代码
public static class TwoStacksQueue {
public Stack<Integer> stackPush;
public Stack<Integer> stackPop;
public TwoStacksQueue() {
stackPush = new Stack<Integer>();
stackPop = new Stack<Integer>();
}
private void pushToPop() {
if (stackPop.empty()) {
while (!stackPush.empty()) {
stackPop.push(stackPush.pop());
}
}
}
public void add(int pushInt) {
stackPush.push(pushInt);
pushToPop();
}
public int poll() {
if (stackPop.empty() && stackPush.empty()) {
throw new RuntimeException("Queue is empty!");
}
pushToPop();
return stackPop.pop();
}
public int peek() {
if (stackPop.empty() && stackPush.empty()) {
throw new RuntimeException("Queue is empty!");
}
pushToPop();
return stackPop.peek();
}
}
两个队列实现栈
思路
像上面那个题目一样,我们肯定是要两个队列来实现栈的。那我们怎么实现呢?
当数组里面的元素过来的时候,我们先压入第一个队列,当要pop的时候我们让第一个队列的元素压入到第二个队列,但是要留下一个,这个是用来返回的,返回之后,然后再把第二个里面的所有元素再倒回第一个队列
代码
public static class TwoQueueStack<T> {
public Queue<T> queue;
public Queue<T> help;
public TwoQueueStack() {
queue = new LinkedList<>();
help = new LinkedList<>();
}
public void push(T value) {
queue.offer(value);
}
public T poll() {
while (queue.size() > 1) {
help.offer(queue.poll());
}
T ans = queue.poll();
Queue<T> tmp = queue;
queue = help;
help = tmp;
return ans;
}
public T peek() {
while (queue.size() > 1) {
help.offer(queue.poll());
}
T ans = queue.poll();
help.offer(ans);
Queue<T> tmp = queue;
queue = help;
help = tmp;
return ans;
}
public boolean isEmpty() {
return queue.isEmpty();
}
}