努力经营当下,直至未来明朗!
普通小孩也要热爱生活!
1. 删除链表中重复的节点
删除链表中重复的节点
1)思路:
① 如果要删除重复的节点,一定要知道第一个重复节点前的节点p以及重复的最后一个结点q。(即前开后闭)
② 找到之后:p.next = q.next 即可。
③ 写一个头节点比较好,如果第一个结点就是重复节点,那头结点其实就可以保证前开后闭。
④ 注意找重复节点的细节!
⑤ 注意循环的条件
⑥ 注意返回值!
2)代码:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode deleteDuplication(ListNode pHead) {
if(pHead == null) {
return pHead;
}
// 首先设定一个头结点
ListNode head = new ListNode(0);
head.next = pHead;
// 这里的话就说明是可以开始寻找重复的区间了
ListNode prev = head;
ListNode last= head.next;
while(last != null) {
while(last.next!=null && last.val!=last.next.val) {
// 此时说明并没有重复,prev和last整体后移
prev = last;
last = last.next;
}
while(last.next!=null && last.val==last.next.val) {
// 此时说明有重复,last后移直到找到最后一个重复的位置
last = last.next;
}
// 来到这里,说明:
// 1. last.next!=null,此时确定一段重复范围(prev,last]
// 2. last.next==null,此时也确定一段范围(prev,last]
// 3. last.next==null,但是没有一段范围
// 判断有没有确定一段范围
if(prev.next != last) {
prev.next = last.next;
}
last = last.next;
}
pHead = head.next;
return pHead;
}
}
2. 包含min函数的栈
包含min函数的栈
1)面试官很容易问:如果弹出第二小、第三小呢?
2)思路:
① 栈:先进后出
② 使用辅助栈结构:辅助栈中只放最小的元素!
③ 所以:辅助栈中的栈顶元素就是最小元素,其次就是第二、第三…可以进行弹栈操作
④ 辅助栈特性:元素个数永远与数据栈中的个数相同;辅助栈栈顶永远保存当前数据栈的最小值;其中,辅助栈中数据可能存在大量重复值。
3)代码:
import java.util.Stack;
public class Solution {
//定义数据栈和辅助栈
Stack<Integer> data_stack = new Stack<>(); // 数据栈
Stack<Integer> min_stack = new Stack<>(); // 辅助栈
// 弹入
public void push(int node) {
// 进行判断后弹入
if(min_stack.isEmpty() || (min_stack.peek()>node)) {
min_stack.push(node);
} else {
min_stack.push(min_stack.peek());
}
// 无论如何数据都要存入数据栈
data_stack.push(node);
}
// 弹出
public void pop() {
data_stack.pop();
min_stack.pop();
}
// 栈顶元素:数据栈栈顶元素
public int top() {
return data_stack.peek();
}
// 最小元素:辅助栈栈顶元素就是min
public int min() {
return min_stack.peek();
}
}
3. 栈的压入、弹出序列
栈的压入、弹出序列
1)思路:
① 弹出序列的第一个元素必定是最后入栈的
② 如果遇到入栈元素与出栈的元素相等,此时开始进行弹出序列,否则持续入栈直至相等;直到发现弹出序列与栈中的元素不相等,此时就继续入栈,重复以上判断操作
③ 直到最后已经压入所有元素,如果此时栈为空就说明是,否则不是!
④ 主要是使用循环实现的。
2)代码:
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
// 首先进行判断
if(pushA==null || popA==null || pushA.length!=popA.length) {
return false;
}
// 遍历pushA,并与popA比较【进行出入栈】
Stack<Integer> stack = new Stack<>();
int i = 0;
int j = 0;
for(; i<pushA.length; i++) {
// 首先进行入栈操作,是一定有的
stack.push(pushA[i]);
// 入栈之后进行判断,栈顶元素是否与popA的首元素相等
// popA首元素是会变化的
// 注意使用循环
while(!stack.isEmpty() && stack.peek()==popA[j]) {
// 如果相等,就进行弹出操作,并且j++
stack.pop();
j++;
}
}
return stack.isEmpty();
}
}
4. 从上往下打印二叉树[层序遍历]
从上往下打印二叉树
1)思路:
使用队列
① 根结点入队列
② 出一个节点 (保存该节点,以便后续访问左右子结点)
③ 访问该节点,并将其左右子节点入队列(一定要注意判空)
④ 然后重复②③步骤就行!(队列为空则访问结束)
2)代码:
import java.util.ArrayList;
import java.util.*;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
// 根据返回类型创建一个返回层序遍历结果的链表(存储值)
ArrayList<Integer> ret = new ArrayList<>();
// 首先进行判断
if(root == null) {
return ret;
}
// 存储的辅助队列(存储节点)
Queue<TreeNode> queue = new LinkedList<>();
// 将root入队列!
queue.offer(root);
// 首先进行遍历:入队列出队列
// 注意保存出队列的值,后续进行访问及其左右子结点时需要
while(!queue.isEmpty()) {
// 出一个节点(注意保存该结点的值)
TreeNode cur = queue.poll();
// 并将弹出的节点保存到结果队列中
ret.add(cur.val);
// 然后将其左右节点压入队列
// 但是注意判空操作
if(cur.left != null) {
queue.offer(cur.left);
}
if(cur.right != null) {
queue.offer(cur.right);
}
}
// 此时返回结果链表
return ret;
}
}