【算法提升—力扣每日一刷】五日总结【12/18--12/22】

文章目录

      • 2023/12/18
        • LeetCode每日一刷:[20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/)
      • 2023/12/19
        • LeetCode每日一刷:[150. 逆波兰表达式求值(后缀表达式运算)](https://leetcode.cn/problems/evaluate-reverse-polish-notation/)
        • 联想思考:如何将中缀表达式转换为后缀表达式?
        • LeetCode今日两刷: [232.双栈模拟队列](https://leetcode.cn/problems/implement-queue-using-stacks/description/)
      • 2023/12/20
        • LeetCode每日一刷:[225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/)
      • 2023/12/21
        • LeetCode每日一刷:[103. 二叉树的锯齿形层序遍历](https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/)
      • 2023/12/22
        • LeetCode每日一刷:[23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/)<同12/09>
      • LeetCode每五日一总结【12/18--12/22】
      • **2023/12/18**
      • **2023/12/19**
      • **2023/12/20**
      • **2023/12/21**
      • **2023/12/22**

在这里插入图片描述

2023/12/18

LeetCode每日一刷:20. 有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成
class Solution {private static final Map<Character,Character> map = new HashMap<Character,Character>(){{put('{','}'); put('[',']'); put('(',')'); put('?','?');}};public boolean isValid(String s) {if(s.length() > 0 && !map.containsKey(s.charAt(0))) return false;LinkedList<Character> stack = new LinkedList<Character>() {{ add('?'); }};for(Character c : s.toCharArray()){if(map.containsKey(c)) stack.addLast(c);else if(map.get(stack.removeLast()) != c) return false;}return stack.size() == 1;}
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以上思路出自

作者:Krahets
链接:https://leetcode.cn/problems/valid-parentheses/
来源:LeetCode(LeetCode)

	public boolean isValid(String s) {// 创建一个栈Stack<Character> stack = new Stack<>();// 遍历字符串中的每一个字符for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);// 如果字符是左括号,则将右括号压入栈中if (c == '(') {stack.push(')');} else if (c == '[') {stack.push(']');} else if (c == '{') {stack.push('}');} else {// 如果字符是右括号,则判断栈中是否有对应的左括号if (!stack.isEmpty() && c == stack.peek()) {stack.pop();} else {// 如果没有对应的左括号,则返回falsereturn false;}}}// 如果栈为空,则返回truereturn stack.isEmpty();}

这是一个 Java 代码,定义了一个名为 isValid 的方法,该方法接受一个字符串 s 作为输入,并返回一个布尔值,表示该字符串是否是一个有效的括号序列。

该方法使用一个堆栈来跟踪在输入字符串中遇到的 opening parentheses(括号、大括号)。当它遇到一个 opening parenthesis 时,将与之对应的 closing parenthesis 压入堆栈。如果它遇到一个 closing parenthesis,它会检查它是否与堆栈的顶部元素匹配。如果它匹配,它会从堆栈中弹出顶部元素。如果不匹配,它会返回 false,表示输入字符串不是有效的括号序列。

在处理完输入字符串中的所有字符后,该方法检查堆栈是否为空。如果为空,这意味着所有括号都已匹配,输入字符串是一个有效的括号序列。如果堆栈不为空,则表示存在未匹配的括号,输入字符串不是一个有效的括号序列。

以下是代码的逐行解释:

  1. 创建一个名为 stack 的空堆栈。
  2. 遍历输入字符串 s 中的每个字符 c
  3. 如果 c 是 opening parenthesis(([{),将与之对应的 closing parenthesis 压入堆栈()]}, respectively)。
  4. 如果 c 是 closing parenthesis,检查它是否与堆栈的顶部元素匹配。
    • 如果它匹配,从堆栈中弹出顶部元素。
    • 如果它不匹配,返回 false,表示输入字符串不是有效的括号序列。
  5. 如果 c 既不是 opening parenthesis 也不是 closing parenthesis,检查它是否与堆栈的顶部元素匹配。
    • 如果它匹配,从堆栈中弹出顶部元素。
    • 如果它不匹配,返回 false,表示输入字符串不是有效的括号序列。
  6. 在处理完输入字符串中的所有字符后,检查堆栈是否为空。
    • 如果为空,返回 true,表示输入字符串是一个有效的括号序列。
    • 如果不为空,返回 false,表示输入字符串不是一个有效的括号序列。

2023/12/19

LeetCode每日一刷:150. 逆波兰表达式求值(后缀表达式运算)

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*''/'
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

示例 3:

输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

提示:

  • 1 <= tokens.length <= 104
  • tokens[i] 是一个算符("+""-""*""/"),或是在范围 [-200, 200] 内的一个整数

逆波兰表达式:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

  • 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 )
  • 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * )

逆波兰表达式主要有以下两个优点:

  • 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
  • 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
	//jdk新语法,不需要写breakpublic int evalRPN(String[] tokens) {//定义一个栈数据结构LinkedList<Integer> stack = new LinkedList<>();//迭代字符串数组中的每一个元素for (String s : tokens) {switch (s) {//如果当前字符为" + ",则将栈顶两个元素弹出,做和运算后再压入栈中case "+" -> {int b = stack.pop();int a = stack.pop();stack.push(a + b);}//如果当前字符串为" - ",则将栈顶两个元素弹出,做差运算后再压入栈中(注意弹栈顺序:先弹栈的做减数)case "-" -> {int b = stack.pop();int a = stack.pop();stack.push(a - b);}//如果当前字符串为" * ",则将栈顶两个元素弹出,做乘积运算后再压入栈中case "*" -> {int b = stack.pop();int a = stack.pop();stack.push(a * b);}//如果当前字符串为" / ",则将栈顶两个元素弹出,做除法运算后再压入栈中(注意弹栈顺序:先弹栈的做除数)case "/" -> {int b = stack.pop();int a = stack.pop();stack.push(a / b);}//如果当前字符串为非运算符,则转为int类型后,压入栈中default -> {stack.push(Integer.parseInt(s));}}}//最后将栈中最后一个也是唯一一个元素返回,即是后缀表达式运算结果return stack.pop();}
//jdk旧语法LinkedList<Integer> stack = new LinkedList<>();for (String s : tokens) {switch (s) {case "+": {int b = stack.pop();int a = stack.pop();stack.push(a + b);break;}case "-": {int b = stack.pop();int a = stack.pop();stack.push(a - b);break;}case "*": {int b = stack.pop();int a = stack.pop();stack.push(a * b);break;}case "/": {int b = stack.pop();int a = stack.pop();stack.push(a / b);break;}default: {stack.push(Integer.parseInt(s));}}}return stack.pop();}
联想思考:如何将中缀表达式转换为后缀表达式?
思路:1. 遇到非运算符 直接拼串
2. 遇到 + - * /- 它的优先级比栈顶运算符高, 入栈,: 栈中是 + 当前是 *- 否则把栈里优先级 >= 它 的都出栈, 它再入栈,: 栈中是 +*, 当前是 -
3. 遍历完成, 栈里剩余运算符依次出栈
4. 如果带()- 左括号直接入栈, 左括号优先设置为0- 右括号就把栈里到左括号为止的所有运算符出栈|   ||   ||   |_____a+b             ab+a+b-c           ab+c-a*b+c           ab*c+a+b*c           abc*+    a+b*c-d         abc*+d-(a+b)*c         ab+c*(a+b*c-d)*e     abc*+d-e*a*(b+c)         abc+*
//计算优先级static int priority(char c) {return switch (c) {case '+', '-' -> 1; // + - 优先级为 1case '*', '/' -> 2; // * / 优先级为 2case '(' -> 0;default -> throw new IllegalArgumentException("输入的参数不合法 " + c);};}static String infixToSuffix(String exp) {//定义一个StringBuilder字符串变量,用于拼接结果集字符串StringBuilder result = new StringBuilder(exp.length());//定义一个栈,用于存放按照规定的优先级规律存放 运算符LinkedList<Character> stack = new LinkedList<>();//遍历字符串参数(中缀表达式)for (int i = 0; i < exp.length(); i++) {//取到表达式中的每一个字符char c = exp.charAt(i);//如果取到的字符为运算符或者括号,则根据规则入栈或者出栈,如果取到的字符是非运算符和括号,则直接参与字符串拼接switch (c) {case '+', '-', '*', '/' -> {//如果栈是空的,则直接将字符串压入栈中if (stack.isEmpty()) {stack.push(c);} else {//如果栈非空,则判断当前运算符的优先级及栈顶运算符优先级,如果当前运算符优先级高于栈顶运算符优先级,则将当前运算符压人栈if (priority(c) > priority(stack.peek())) {stack.push(c);} else {//如果当前运算符优先级小于或等于栈顶运算符优先级,则将栈顶运算符弹栈后拼接到结果集字符串中,并循环比较,如果栈被弹空,停止循环while (!stack.isEmpty() && priority(c) <= priority(stack.peek())) {result.append(stack.pop());}//最后将当前运算符压入栈中stack.push(c);}}}//如果当前字符为左括号,则直接压入栈中case '(' -> {stack.push('(');}//如果当前运算符是右括号,则将栈中左括号上面的所有运算符弹栈后拼接到结果集字符串中case ')' -> {while (!stack.isEmpty()&& stack.peek()!='('){result.append(stack.pop());}//最后将左括号从栈中弹出stack.pop();}//字符为非运算符,直接拼接到结果集字符串中default -> result.append(c);}}//当字符串中每个字符都被迭代后,将栈中还未弹栈的运算符弹出并拼接到结果集字符串中while (!stack.isEmpty()){result.append(stack.pop());}//返回StringBuilder的toString字符串类型return result.toString();}

LeetCode今日两刷: 232.双栈模拟队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

示例 1:

输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示:

  • 1 <= x <= 9
  • 最多调用 100pushpoppeekempty
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

进阶:

  • 你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。

给LeetCode题目用的自实现栈,可以定义为静态内部类

class ArrayStack<E> {private E[] array;private int top; // 栈顶指针@SuppressWarnings("all")public ArrayStack(int capacity) {this.array = (E[]) new Object[capacity];}public boolean push(E value) {if (isFull()) {return false;}array[top++] = value;return true;}public E pop() {if (isEmpty()) {return null;}return array[--top];}public E peek() {if (isEmpty()) {return null;}return array[top - 1];}public boolean isEmpty() {return top == 0;}public boolean isFull() {return top == array.length;}
}

参考解答,注意:题目已说明

  • 调用 push、pop 等方法的次数最多 100
public class E04Leetcode232 {/*队列头      队列尾s1       s2顶   底   底   顶abcpush(a)push(b)push(c)pop()*/ArrayStack<Integer> s1 = new ArrayStack<>(100);ArrayStack<Integer> s2 = new ArrayStack<>(100);public void push(int x) {s2.push(x);}public int pop() {if (s1.isEmpty()) {while (!s2.isEmpty()) {s1.push(s2.pop());}}return s1.pop();}public int peek() {if (s1.isEmpty()) {while (!s2.isEmpty()) {s1.push(s2.pop());}}return s1.peek();}public boolean empty() {return s1.isEmpty() && s2.isEmpty();}}

提交版代码:

class MyQueue ArrayStack<Integer> s1 = new ArrayStack<>(100);ArrayStack<Integer> s2 = new ArrayStack<>(100);public void push(int x) {s1.push(x);}public int pop() {if (s2.isEmpty()) {while (!s1.isEmpty()) {s2.push(s1.pop());}}return s2.pop();}public int peek() {if (s2.isEmpty()) {while (!s1.isEmpty()) {s2.push(s1.pop());}}return s2.peek();}public boolean empty() {return s1.isEmpty() && s2.isEmpty();}static class ArrayStack<E>{private final E[] stack;private int top;@SuppressWarnings("ALL")public ArrayStack(int capacity) {stack = (E[]) new Object[capacity];}public boolean push(E value) {if (isFull()) {return false;}stack[top++] = value;return true;}public E pop() {if(isEmpty()){return null;}return stack[--top];}public E peek() {if(isEmpty()){return null;}return stack[top-1];}public boolean isEmpty() {return top == 0;}public boolean isFull() {return top == stack.length;}   }
}/*** Your MyQueue object will be instantiated and called as such:* MyQueue obj = new MyQueue();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.peek();* boolean param_4 = obj.empty();*/

LeetCode官方题解

class MyQueue {Deque<Integer> inStack;Deque<Integer> outStack;public MyQueue() {inStack = new ArrayDeque<Integer>();outStack = new ArrayDeque<Integer>();}public void push(int x) {inStack.push(x);}public int pop() {if (outStack.isEmpty()) {in2out();}return outStack.pop();}public int peek() {if (outStack.isEmpty()) {in2out();}return outStack.peek();}public boolean empty() {return inStack.isEmpty() && outStack.isEmpty();}//将输入栈中的元素弹栈并压入输出栈private void in2out() {while (!inStack.isEmpty()) {outStack.push(inStack.pop());}}
}作者:LeetCode官方题解
链接:https://leetcode.cn/problems/implement-queue-using-stacks/
来源:LeetCodeLeetCode

思路

将一个栈当作输入栈,用于压入 push 传入的数据;另一个栈当作输出栈,用于 pop 和 peek 操作。

每次 pop 或 peek 时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。


2023/12/20

LeetCode每日一刷:225. 用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppopempty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false

注意:

  • 你只能使用队列的基本操作 —— 也就是 push to backpeek/pop from frontsizeis empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

提示:

  • 1 <= x <= 9
  • 最多调用100pushpoptopempty
  • 每次调用 poptop 都保证栈不为空

**进阶:**你能否仅用一个队列来实现栈。

提交代码

class MyStack {ArrayQueue5<Integer> queue = new ArrayQueue5<>(100);private int size = 0;public void push(int x) {queue.offer(x);for(int i =0;i<size;i++){queue.offer(queue.poll());}size++;}public int pop() {size--;return queue.poll();}public int top() {return queue.peek();}public boolean empty() {return queue.isEmpty();}static class ArrayQueue5<E>{private final E[] array;int head = 0;int tail = 0;@SuppressWarnings("all")public ArrayQueue5(int capacity) {/*//抛异常if ((capacity & capacity - 1) != 0) {throw new IllegalArgumentException("请传入容量为2的N次方的容量参数");}*///增大容量为大于当前参数的最小2的n次方    13 -> 16   22 -> 32if ((capacity & capacity - 1) != 0) {int n = (int) ((Math.log10(capacity) / Math.log10(2)) + 1);//计算大于参数的最小2的n次方的ncapacity = 1 << n;  //左移运算符,相当于乘2 , 1 << n相当于 2^nSystem.out.println(capacity);}array = (E[]) new Object[capacity];}public boolean offer(E value) {if (isFull()) {return false;}//使用位运算,规律:当一个数对2的整数次的数取模时,余数=这个数 &(按位与) 2的整数次-1//   666 % 8 = 666 & 7/*求模运算:- 如果除数是 2 的 n 次方- 那么被除数的后 n 位即为余数 (模)- 求被除数的后 n 位方法: 与 2^n-1 按位 与*/array[tail & array.length - 1] = value;tail++;return true;}public E poll() {if (isEmpty()) {return null;}E value = array[head & array.length - 1];head++;return value;}public E peek() {if (isEmpty()) {return null;}E value = array[head & array.length - 1];return value;}public boolean isEmpty() {return tail == head;}public boolean isFull() {return (tail - head) == array.length;}}
}/*** Your MyStack object will be instantiated and called as such:* MyStack obj = new MyStack();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.top();* boolean param_4 = obj.empty();*/

官方题解

class MyStack {Queue<Integer> queue;/** Initialize your data structure here. */public MyStack() {queue = new LinkedList<Integer>();}/** Push element x onto stack. */public void push(int x) {int n = queue.size();queue.offer(x);for (int i = 0; i < n; i++) {queue.offer(queue.poll());}}/** Removes the element on top of the stack and returns that element. */public int pop() {return queue.poll();}/** Get the top element. */public int top() {return queue.peek();}/** Returns whether the stack is empty. */public boolean empty() {return queue.isEmpty();}
}

一个队列
方法一使用了两个队列实现栈的操作,也可以使用一个队列实现栈的操作。

使用一个队列时,为了满足栈的特性,即最后入栈的元素最先出栈,同样需要满足队列前端的元素是最后入栈的元素。

入栈操作时,首先获得入栈前的元素个数 n,然后将元素入队到队列,再将队列中的前 n 个元素(即除了新入栈的元素之外的全部元素)依次出队并入队到队列,此时队列的前端的元素即为新入栈的元素,且队列的前端和后端分别对应栈顶和栈底。

由于每次入栈操作都确保队列的前端元素为栈顶元素,因此出栈操作和获得栈顶元素操作都可以简单实现。出栈操作只需要移除队列的前端元素并返回即可,获得栈顶元素操作只需要获得队列的前端元素并返回即可(不移除元素)。

由于队列用于存储栈内的元素,判断栈是否为空时,只需要判断队列是否为空即可。

2023/12/21

LeetCode每日一刷:103. 二叉树的锯齿形层序遍历

给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

示例 1:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[20,9],[15,7]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目在范围 [0, 2000]
  • -100 <= Node.val <= 100
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {//定义一个存放结果集的链表List<List<Integer>> result = new ArrayList<>();//如果根节点为空,则直接返回空结果集if (root == null) {return result;}//定义一个队列Queue<TreeNode> queue = new LinkedList<>();//将根节点放入队列queue.offer(root);//记录每层节点个数int c = 1;//记录层数,以便对不同层做不同操作boolean odd = true;//默认为奇数层//如果队列非空while (!queue.isEmpty()) {//定义一个变量记录下一层节点个数int n = 0;//定义一个双端队列,用来存放每一层的节点Deque<Integer> lever = new LinkedList<>();//遍历当前层的每一个节点for (int i = 0; i < c; i++) {//将节点从队列中弹出TreeNode treeNode = queue.poll();if(odd){//如果为奇数层,则从尾部添加,正序lever.offerLast(treeNode.val);}else {//如果是偶数层,则从头部添加,逆序lever.offerFirst(treeNode.val);}//如果节点有左孩子,则加入队列if (treeNode.left != null) {queue.offer(treeNode.left);n++;}//如果节点有右孩子,则加入队列if (treeNode.right != null) {queue.offer(treeNode.right);n++;}}//将下一层节点数赋值给cc = n;//将每一层的节点组成的双端队列转换为链表加入到结果集result.add(new LinkedList<>(lever));//层数取反,奇数层变偶数层    偶数层变奇数层odd=!odd;}return result;}static class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) {this.val = val;}TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}}

这段Java代码定义了一个名为zigzagLevelOrder的方法,该方法接受一个TreeNode类型的参数root,并返回一个List<List<Integer>>类型的结果。该方法的作用是按照zigzag顺序(即先从左到右,再从右到左)遍历二叉树的每一层,并将每一层的节点值存储在一个List<Integer>类型的列表中。

以下是代码的详细解释:

  1. 定义一个存放结果集的链表result,以及一个存放节点的队列queue
  2. 如果根节点为空,则直接返回空结果集。
  3. 定义一个变量c来记录每层节点的个数,以及一个布尔变量odd来记录当前是奇数层还是偶数层。
  4. 定义一个双端队列lever来存放每一层的节点。
  5. 遍历当前层的每一个节点,将节点从队列中弹出,并将其值添加到lever队列中。如果是奇数层,则从队列尾部添加,即正序;如果是偶数层,则从队列头部添加,即逆序。
  6. 如果当前节点的左孩子不为空,则将其加入队列queue中。如果当前节点的右孩子不为空,则将其加入队列queue中。
  7. 计算下一层节点的个数n,并将队列queue中的节点个数赋值给c
  8. lever队列中的节点值组成一个List<Integer>类型的列表,并将其添加到结果集result中。
  9. 更新odd变量,使其在奇数层和偶数层之间切换。
  10. 循环执行步骤5到步骤9,直到队列为空。
  11. 返回结果集result

此外,代码中还定义了一个名为TreeNode的类,用于表示二叉树的节点。该类包含一个整数值val,以及两个指向子节点的引用leftright

2023/12/22

LeetCode每日一刷:23. 合并 K 个升序链表<同12/09>

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

提示:

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i]升序 排列
  • lists[i].length 的总和不超过 10^4
/*** 小顶堆*/
public class MinHeap {ListNode[] array;int size;public MinHeap(int capacity) {array = new ListNode[capacity];}public boolean offer(ListNode value) {if (isFull()) {return false;}int child = size++;int father = (child - 1) / 2;while (child > 0 && value.val < array[father].val) {array[child] = array[father];child = father;father = (child - 1) / 2;}array[child] = value;return true;}public ListNode poll() {if (isEmpty()) {return null;}//1.交换堆顶元素与最后一个元素,删除最后一个元素swap(0, size - 1);size--;ListNode e = array[size];array[size] = null;// help GC//2.将推顶元素与其孩子不断比较,到他合适位置down(0);return e;}private void down(int father) {int left = father * 2 + 1;int right = left + 1;int min = father;// 假设父元素最小if (left < size && array[left].val < array[min].val) {min = left;}if (right < size && array[right].val < array[min].val) {min = right;}if (min != father) {// 说明发生了交换,则有孩子比父亲大swap(min, father);down(min);}}private void swap(int i, int j) {ListNode t = array[j];array[j] = array[i];array[i] = t;}public boolean isEmpty() {return size == 0;}public boolean isFull() {return size == array.length;}
}
//使用小顶堆解决
public ListNode mergeKLists(ListNode[] lists) {/*          p1*          1   5   9   7   null*          p2*          5   6   8   9   null*          p3*          3   5   7   8   null*小顶堆:   1	5	3空链表    null->*/MinHeap minHeap = new MinHeap(lists.length);for (ListNode h : lists) {if (h != null) {minHeap.offer(h);}}//新链表的哨兵节点ListNode s = new ListNode(-1, null);ListNode p = s;while (!minHeap.isEmpty()) {ListNode min = minHeap.poll();p.next = min;p = min;if(min.next!=null){minHeap.offer(min.next);//将链表的下一个节点加入小顶堆}}return s;}

使用小顶堆数据结构,先将链表中的头节点都加入小顶堆中,实例化一个新的链表【直接实例化一个新链表的哨兵节点即可】,定义一个指针,用来操作新链表,如果小顶堆不为空,则将小顶堆中poll出来的元素加入到新链表中,指针指向新的节点且将poll出来的节点的下一个节点再次加入到小顶堆(前提:下一节点存在),循环操作,直到小顶堆为空,说明已将全部节点转移到新链表,返回哨兵节点的next即可!

LeetCode每五日一总结【12/18–12/22】

2023/12/18

  1. 20.有效的括号

​ 定义一个名为 isValid 的方法,该方法接受一个字符串 s 作为输入,并返回一个布尔值,表示该字符串是否是一个有效的括号序列。

​ 该方法使用一个堆栈来跟踪在输入字符串中遇到的 opening parentheses(括号、大括号)。当它遇到一个 opening parenthesis 时,将与之对应的 closing parenthesis 压入堆栈。如果它遇到一个 closing parenthesis,它会检查它是否与堆栈的顶部元素匹配。如果它匹配,它会从堆栈中弹出顶部元素。如果不匹配,它会返回 false,表示输入字符串不是有效的括号序列。

​ 在处理完输入字符串中的所有字符后,该方法检查堆栈是否为空。如果为空,这意味着所有括号都已匹配,输入字符串是一个有效的括号序列。如果堆栈不为空,则表示存在未匹配的括号,输入字符串不是一个有效的括号序列。

2023/12/19

  1. 150.逆波兰表达式求值(后缀表达式运算)
​	使用**栈**数据结构,遍历逆波兰表达式数组,将**非运算符字符**压入栈中,如果遍历到的元素为运算符,则将**栈中弹出两个元素进行运算操作**,最后**将运算结果再次压入栈中**,直到遍历完整个字符串,将栈中最后一个元素弹出并返回即可!
  1. 联想思考:如何将中缀表达式转换为后缀表达式
思路:
      1. 遇到非运算符 直接拼串2. 遇到 + - * /- 它的优先级比栈顶运算符高, 入栈,: 栈中是 + 当前是 *- 否则把栈里优先级 >= 它 的都出栈, 它再入栈,: 栈中是 +*, 当前是 -3. 遍历完成, 栈里剩余运算符依次出栈4. 如果带()- 左括号直接入栈, 左括号优先设置为0- 右括号就把栈里到左括号为止的所有运算符出栈|   ||   ||   |_____
a+b             ab+
a+b-c           ab+c-
a*b+c           ab*c+
a+b*c           abc*+    
a+b*c-d         abc*+d-
(a+b)*c         ab+c*
(a+b*c-d)*e     abc*+d-e*
a*(b+c)         abc+*
  1. 232.双栈模拟队列
思路:将一个栈当作输入栈,用于压入 push 传入的数据;另一个栈当作输出栈,用于 pop 和 peek 操作。每次 pop 或 peek 时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。

2023/12/20

  1. 225.用队列实现栈

思路:

使用一个队列

使用一个队列时,为了满足栈的特性,即最后入栈的元素最先出栈,同样需要满足队列前端的元素是最后入栈的元素。

入栈操作时,首先获得入栈前的元素个数 n,然后将元素入队到队列,再将队列中的前 n 个元素(即除了新入栈的元素之外的全部元素)依次出队并入队到队列,此时队列的前端的元素即为新入栈的元素,且队列的前端和后端分别对应栈顶和栈底。

由于每次入栈操作都确保队列的前端元素为栈顶元素,因此出栈操作和获得栈顶元素操作都可以简单实现。出栈操作只需要移除队列的前端元素并返回即可,获得栈顶元素操作只需要获得队列的前端元素并返回即可(不移除元素)。

由于队列用于存储栈内的元素,判断栈是否为空时,只需要判断队列是否为空即可。

2023/12/21

  1. 103.二叉树的锯齿形层序遍历
思路:使用**队列**数据结构,先将二叉树的根节点入队,并定义一个变量记录二叉树每一层的节点个数,用于遍历每一层的节点,再定义一个双端队列,每次从队列出队的节点,根据层数的奇偶不同,选择从双端队列头部添加或者尾部添加,以此实现锯齿形层序遍历,判断如果从队列出队的节点存在左右孩子,则将其左右孩子入队列,循环此操作,直到队列为空。

2023/12/22

  1. 23.合并 K 个升序链表<小顶堆实现>

使用小顶堆数据结构,先将链表中的头节点全都加入小顶堆中,实例化一个新的链表【直接实例化一个新链表的哨兵节点即可】,定义一个指针,用来操作新链表,如果小顶堆不为空,则将小顶堆中poll出来的元素加入到新链表中,指针指向新的节点且将poll出来的节点的下一个节点再次加入到小顶堆(前提:下一节点存在),循环操作,直到小顶堆为空,说明已将全部节点转移到新链表,返回哨兵节点的next即可!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360396.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CompletableFuture不能被打断

我已经写了很多有关InterruptedException和中断线程的文章 。 简而言之&#xff0c;如果您没有Future.cancel()调用Future.cancel()那么Future将终止待处理的get() &#xff0c;但还将尝试中断基础线程。 这是一个非常重要的功能&#xff0c;可以更好地利用线程池。 我还写信总…

crio电压采集 labview_NI cDAQ917采集温度方法

NI cDAQ-9171是一款由总线供电的单槽NI CompactDAQ USB机箱&#xff0c;适合较小的便携式传感器测量系统。cDAQ-9171可与50多款专用测量模块配合使用&#xff0c;用于构建模拟输出、数字I/O或计数器/定时器测量系统。这些模块适用于各种传感器测量&#xff0c;包括热电偶、RTD、…

android finish 区别,Android Activity类finish、onDestory和System.exit介绍

image.pngfinish函数Activity.finish()Call this when your activity is done and should be closed.在你的activity动作完成的时候&#xff0c;或者Activity需要关闭的时候&#xff0c;调用此方法。当调用此方法的时候&#xff0c;系统只是将最上面的Activity移出了栈&#xf…

在JVM中记录世界停顿

不同的事件可能导致JVM暂停所有应用程序线程。 这种暂停称为世界停止&#xff08;STW&#xff09;暂停。 触发STW暂停的最常见原因是垃圾回收&#xff08; 例如github中的示例 &#xff09;&#xff0c;但是不同的JIT操作&#xff08; 示例 &#xff09;&#xff0c;偏向锁吊销…

jOOQ与Hibernate:何时选择哪个

Hibernate已成为Java生态系统中的事实上的标准&#xff0c;事实上&#xff0c; 如果标准对您很重要 &#xff0c;并且如果您将JCP与ISO&#xff0c;ANSI&#xff0c;IEEE等置于同一级别&#xff0c;那么Hibernate也是实际的JavaEE标准实现。 本文的目的不是讨论标准&#xff0…

linux怎么才能算telnet成功_怎么表白才算成功呢

要怎样表白才算成功呢&#xff1f;其实如果对方也有点喜欢你的&#xff0c;对你有点感觉的&#xff0c;不管怎样表白&#xff0c;你都会成功的&#xff0c;相反&#xff0c;如果对方本身就对你没感觉的&#xff0c;不管你要怎么轰轰烈烈的表白&#xff0c;你都不会成功。下面&a…

我们真的仍然需要32位JVM吗?

即使到了今天&#xff08;2015年&#xff09;&#xff0c;我们仍然有两个版本或Oracle HotSpot JDK –已调整为32或64位体系结构。 问题是我们是否真的想在服务器甚至笔记本电脑上使用32位JVM&#xff1f; 我们应该有很受欢迎的意见&#xff01; 如果只需要较小的堆&#xff0c…

html js点击字图片下拉,JavaScript实现文字与图片拖拽效果的方法

本文实例讲述了JavaScript实现文字与图片拖拽效果的方法。分享给大家供大家参考。具体实现方法如下&#xff1a;JavaScript实现文字与图片的拖拽效果*{padding:0;margin:0;}.tips{position:absolute;background:#eee;}图片可以拖动脚本之家拖动链接也可以var $idfunction(id){r…

html设置页面的高度和宽度,web显示页面有图像上设置高度和宽度很重要

因此即使浏览器只有HTML&#xff0c;它仍然能够分配适当的空间。所以我们可以修改成以下内容&#xff1a;最近我们发现谷歌浏览器对图片设置有一定的修改&#xff0c;它主要在图像上进行设置width和设置height属性&#xff0c;以防止布局发生变化并改善网站访问者的体验。Web性…

磁盘空间管理工具FolderSizes

现在的硬盘已经到了用TB来计量的级别&#xff0c;但也会感觉在不知不觉间空间竟然不够用了&#xff01;到底什么东西占用了我们这么多的磁盘空间呢? 这个软件可以帮你快速进行分析。FolderSizes 企业版是一款优秀的磁盘管理工具&#xff0c;它可以有效地帮助我们快速的查看并统…

vscode修改python终端_panda3d是python的一个高级的3D 渲染和游戏开发框架

1 介绍1.1 开发维护者:迪士尼VR工作室和卡耐基梅隆娱乐技术中心。1.2 是一个3D游戏引擎和一个 3D 渲染和游戏开发库。1.3 可以在这个框架下使用 Python 和 C 。1.4 Panda3D 是开源软件&#xff0c; 它的许可证让它可以用于任何用途&#xff0c; 包括商业用途。1.5 是python的三…

HTMl和css项目总结,HTML+CSS项目开发总结

好几天没更新博客了&#xff0c;刚实战完一个HTMLCSS的简单项目。经过几天的摸索&#xff0c;发现收益良多。之前只是单纯得写demo&#xff0c;看知识点&#xff0c;没有亲自实战项目。但实战过后才会了解&#xff0c;如何才能更好地提升自己的技术。针对这次项目开发&#xff…

HDU--4768

题目&#xff1a; Flyer 原题链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid4768 分析&#xff1a;二分。只需要注意到最多只有一个为奇数&#xff0c;则可以首先求出学生获得的总的传单数&#xff0c;为奇数时&#xff0c;二分找到答案。 1 #include<cstdio&…

js return的值取不到_【JS基础】隐式转换(一)

开篇JS作为一门动态语言十分灵活&#xff0c;但是伴随而来的弱类型隐式转化的问题让我们十分头疼。隐式作为一个大课题&#xff0c;很难用一个很简短的篇幅把JS的隐式转换讲解的十分清楚。所以我选择用多次少量的策略进行梳理&#xff0c;争取让你每看完一篇都会有加深对于JS隐…

语句 查询每个人每个科目的最高分_转行数据分析师专栏(SQL篇)-05多表查询...

数据表&#xff08;4张&#xff09;及数据情况&#xff1a;搭建数据表数据参考&#xff1a;空杯希望&#xff1a;转行数据分析师专栏&#xff08;SQL篇&#xff09;-01SQL入门​zhuanlan.zhihu.com一、表的加法1、先新建一个表course1&#xff08;和course表数据结构一致&#…

plsql 设置鼠标行执行_如何制作键盘鼠标产品质量合格证

鼠标前盘属于办公用品套装&#xff0c;一般会一起销售&#xff0c;但是也不排除分开销售&#xff0c;无论是哪种方式键盘鼠标在生产销售时都需要携带对应产品质量合格证&#xff0c;对产品进行简单的说明&#xff0c;更能保障消费者的权益。那么如何制作产品质量合格证呢&#…

第四章例4-2

/* 输入一批学生的成绩&#xff0c;以负数作为结束标志&#xff0c;计算平均成绩&#xff0c;并统计不及格人数 */ #include<stdio.h> int main(void) {int count,num;double grade,total;num0;total0;count0;printf("Enter grades:");scanf_s("%lf"…

html.action 访问分部视图,MVC+EF 随笔小计——分部视图(Partial View)及Html.Partial和Html.Action差异...

Partial View指可以应用于View中以作为其中一部分的View的片段(类似于之前的user control), 可以像类一样&#xff0c;编写一次&#xff0c; 然后在其他View中被反复使用。一般放在"Views/Shared"文件夹中以共享。创建Partial View&#xff1a;一般直接右键"Vie…

svm核函数gamma参数_非线性SVM与核函数

前面几篇我们介绍的都是线性支持向量机&#xff0c;换句话说&#xff0c;我们总可以用一条线或一个超平面将数据进行分割。如下图所示&#xff1a;但在更多情况下&#xff0c;有些数据是无法进行线性分割的。比如下面的例子&#xff1a;也就是说&#xff0c;你永远无法用一条直…

anychart说明文档

今天学习anychart&#xff0c;在慧都控件网上看有关文档&#xff0c;模仿试着做了个demo&#xff0c;发现慧都空间网的“Flash图表AnyChart应用教程六&#xff1a;创建圆形仪表”里的指针“<pointer type"bar" value"35" color"Gray" />”…