算法
class MyQueue {
Stack<Integer> in;
Stack<Integer> out;
//构造器
public MyQueue() {
in = new Stack<>();
out = new Stack<>();
}
//入队到末尾
public void push(int x) {
in.push(x);
}
//出队
public int pop() {
//先进先出
//in的元素放入out里面然后pop就能达到先进先出的目的,元素顺序都被调转了
change();
return out.pop();
}
//返回队列开头元素
public int peek() {
change();
return out.peek();
}
//判空
public boolean empty() {
return in.isEmpty() && out.isEmpty();
}
//写一个方法:做将元素从in转到out
public void change(){
//出队的首要条件是:out为空
if(!out.isEmpty()) return;
while(!in.isEmpty()){
out.push(in.pop());
}
}
}
class MyStack {
Deque<Integer> que;
public MyStack() {
que = new ArrayDeque<>();
}
//每次都加到最前面(只能使用标准操作)
public void push(int x) {
que.push(x);
int size = que.size();
//我们无需移动刚进来的数
while(size-- >1){
que.push(que.pop());
}
}
//先进后出:由于我们的添加操作,导致最先进来的一定在最左边
public int pop() {
return que.pop();
}
public int top() {
return que.peek();
}
public boolean empty() {
return que.isEmpty();
}
}
class Solution {
public boolean isValid(String s) {
//用栈来做:思路就跟消消乐一样
Stack<Character> stack = new Stack<>();
int len = s.length();
for(int i = 0;i<len;i++){
char ch = s.charAt(i);
if(ch == '('){
stack.push(')');
}else if(ch == '['){
stack.push(']');
}else if(ch == '{'){
stack.push('}');
}else if(stack.isEmpty() || stack.peek()!=ch){
return false;
}else{
stack.pop();
}
}
return stack.isEmpty();
}
}
class Solution {
public String removeDuplicates(String s) {
//依旧用栈来做
Stack<Character> stack = new Stack<>();
int len = s.length();
for(int i = 0;i<len;i++){
char ch = s.charAt(i);
//相同则出栈
if(!stack.isEmpty() && stack.peek()==ch){
char ca = stack.pop();
//System.out.println("pop: " + ca + ": " + i);
continue;
}
stack.push(ch);
//System.out.println("push: " + ch + ": " + i);
}
String res = "";
while(!stack.isEmpty()){
res = stack.pop() + res;
//System.out.println(res);
}
return res;
}
}
class Solution {
public int evalRPN(String[] tokens) {
//很显然使用栈来解决
Stack<Integer> stack = new Stack<>();
for(String s : tokens){
if(s.equals("+")){
stack.push(stack.pop() + stack.pop());
}else if(s.equals("-")){
stack.push(-stack.pop() + stack.pop());
}else if(s.equals("*")){
stack.push(stack.pop() * stack.pop());
}else if(s.equals("/")){
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
}else{
//转换值
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
}
class Solution {
//为什么说这道题是单调队列?
//很明显,在几个窗口里面,我们需要维护这些窗口里面的一个单调值(这道题来说就是最大值)
//利用单调队列来做,可以实现入队出队,以及维护我们需要的这个单调情况这些操作
//而java里面可以通过双端队列来实现
public int[] maxSlidingWindow(int[] nums, int k) {
Deque<Integer> deque = new LinkedList<>();
int n = nums.length;
//有n个数,只能看到k个数字,res只需要最多n-k个即可
int[] res = new int[n-k+1];
int index = 0;
//由于我们不好直接把值放入,因此选择把下标放入队列中
for(int i = 0;i<n;i++){
//不在窗口内的元素就要出队了
while(!deque.isEmpty() && deque.peek() < i-k+1){
deque.poll();
}
//与队列内的元素进行比较,保证单调递增
while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]){
deque.pollLast();
}
deque.offer(i);
//开始记录最值
if(i>=k-1){
res[index++] = nums[deque.peek()];
}
}
return res;
}
}
class Solution {
public int[] topKFrequent(int[] nums, int k) {
//利用Map存元素和次数,然后利用大顶堆或小顶堆来实现
Map<Integer,Integer> map = new HashMap<>();
for(int i : nums){
map.put(i,map.getOrDefault(i,0)+1);
}
//大顶堆的写法
PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2) -> pair2[1] - pair1[1]);
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
pq.add(new int[]{entry.getKey(),entry.getValue()});
}
int[]res = new int[k];
for(int i = 0;i<k;i++){
res[i] = pq.poll()[0];
}
return res;
}
}
今日算法思考
其余的题目基本上使用栈即可解决,思想也比较简单,大致上就是通过栈的特性,达到类似相消的效果。
值得一说的就是“滑动窗口最大值”这道题
我们通过队列来模拟窗口,当遍历达到窗口长度的时候,就得准备挪动窗口,我们要边挪动窗口边找到窗口内最大值,而队列内维护是下标。
补充知识点
MySQL
锁
对行级锁/记录锁的理解
分类:行锁,间隙锁,临键锁
这里会涉及到InnoDB引擎解决幻读问题,使用到间隙锁和临键锁来解决幻读问题
存储引擎
InnoDB如何解决幻读问题
MyISAM和InnoDB区别