class 027 堆结构常见题目

news2024/11/18 3:23:28

这篇文章是看了“左程云”老师在b站上的讲解之后写的, 自己感觉已经能理解了, 所以就将整个过程写下来了。

这个是“左程云”老师个人空间的b站的链接, 数据结构与算法讲的很好很好, 希望大家可以多多支持左程云老师, 真心推荐.
https://space.bilibili.com/8888480?spm_id_from=333.999.0.0

1. 题目一:实现 K 个链表的合并

1.1 题目描述

在这里插入图片描述

有若干个链表, 然后将所有的链表的头结点都放到一个数组 arr[] 中, 例子:arr[] = {3, 1, null, 5}.
每一个数组中的头结点后面还连着链表之后的结点, 是一整个链表. 然后将所有的链表都进行合并, 按照顺序串起来.

如下图, null 表示这个链表是空的.

在这里插入图片描述

1.2 解法

1.2.1 暴力解法

首先来说暴力解法, 开始先准备一个容器, 需要将所有的节点(假设有 n 个) 都放到容器中, 这个的空间复杂度是:O(n) 然后进行排序, 排序过程的时间复杂度是:O(n * log(n)). 然后将所有的节点都串起来(遍历一遍), 最后的时间复杂度是:O(n * log(n)) + O(n) -> O(n * log(n)).

1.2.2 利用堆结构的解法(逻辑实现)

利用堆结构, 将 arr[] 数组中所有的头结点存储的头结点都放到堆结构中, 而且这个堆结构是一个小根堆.

  1. 按照上面图片的例子:将 1, 3, 5, null(放不放都一样), 全部都放到小根堆中,
  2. 然后将小根堆中最小的节点弹出(肯定是根节点 1 了), 因为这是一个链表, 可以通过 next 指针找到 1 的下一个节点(是 8). 此时设置一个变量 head 指向最开始弹出来的 1.
  3. 然后将 8 放到小根堆中, 利用 JDK 中自带的 PriorityQueue类, 这样可以在实现加入和弹出的操作的同时进行自动的调整. 此时小根堆中有 3, 5, 8 .然后设置一个变量 pre, 指向当前弹出的节点, 因为需要直到当前走到了哪里, 这样好进行下一个节点的连接.
  4. 然后继续弹出堆中最小的节点 3, 所以将 pre.next 指针连接到 3, 然后将 pre 指向这个 3 节点,
  5. 然后继续将 3 节点的下一个节点放入小根堆中.
  6. 以后重复上述操作, 直到小根堆中没有任何东西位为止.

1.2.3 利用堆结构的解法(代码实例)

所有需要注意的地方都在注释中.

// 测试链接:https://www.nowcoder.com/practice/65cfde9e5b9b4cf2b6bafa5f3ef33fa6
// 不要提交这个类  
public static class ListNode {  
    public int val;  
    public ListNode next;  
}  
  
// 提交以下的方法  
public static ListNode mergeKLists(ArrayList<ListNode> arr) {  
    // 小根堆  
    PriorityQueue<ListNode> heap = new PriorityQueue<>((a, b) -> a.val - b.val);  
    for (ListNode h : arr) {  
       // 遍历所有的头!  
       if (h != null) {  
          heap.add(h);  // 将所有的头结点都加入到小根堆中.  
       }  
    }  
    if (heap.isEmpty()) {  
       return null;       // 若是为“空”, 直接返回  
    }  
    // 先弹出一个节点,做总头部  
    ListNode h = heap.poll();     
    ListNode pre = h;      // 将“pre”指向最开始的“h”指向的节点  
    if (pre.next != null) {   // 只要当前节点的下一个节点不是“空”, 就将其压入到堆中.  
       heap.add(pre.next);  
    }  
    while (!heap.isEmpty()) {       // 只要“堆”中还有链表节点.就不会停止  
       ListNode cur = heap.poll();  // 将“cur”指向从堆中弹出来的节点.  
       pre.next = cur;              // 将pre的下一个节点指向cur指向的节点  
       pre = cur;                   // 然后将pre指向cur指向的节点.  
       if (cur.next != null) {  
          heap.add(cur.next);     // 若是cur的下一个节点不是“空”, 就将其加入到堆中.  
       }  
    }  
    return h;                         // 最后返回总的头结点  
}

1.2.4 复杂度分析

假设这个题目中有 n 个节点, k 条链表

暴力方法:时间复杂度:
先设置一个容器, 然后遍历一遍(时间复杂度:O(n)),
然后将其进行排序(时间复杂度:(O(n * log(n)))), 最后将所有链表节点串起来(时间复杂度:O(n)).
所以按照时间复杂度取最高阶的定义:这个方法的时间复杂度是:O(n *log(n)).

空间复杂度:因为需要一个能存放所有节点的容器, 所以空间复杂度:O(n).

使用堆结构的方法:时间复杂度:
开始的时候我将所有的链表的头结点(k 个)都放到堆中, 所以将来堆中的节点个数一定不会超过 k 个, 因为我永远的弹出一个, 然后立刻进去一个, 假设按照最差的情况来估计, 插入和弹出过程的时间复杂度是:log(k). 又因为有 n 个节点, 所以对应的时间复杂度是:O(n * log(k)).

空间复杂度:O(k).(因为我的堆中永远不会超过 k 个元素).

1.2.5 用归并的方式做

这里给出代码, 就不做解释了.(只是将其分解为以前讲过的合并两条有序链表的).

public static class ListNode {  
  int val;  
  ListNode next;  
  
  ListNode(int x) {  
      val = x;  
      next = null;  
  }  
  
}  
  
  
public static ListNode mergeKLists(ArrayList<ListNode> lists) {  
    return digui(lists, 0, lists.size() - 1);  
}  
  
public static ListNode digui(ArrayList<ListNode> lists, int left, int right) {  
    if (left > right)  
        return null;  
    else if (left == right)  
        return lists.get(left);  
    else {  
        int mid = (left + right) / 2;  
  
        return mergeTwo(digui(lists, left, mid), digui(lists, mid + 1, right));  
    }  
  
}  
  
public static ListNode mergeTwo(ListNode list1, ListNode list2) {  
    if (list1 == null)  
        return list2;  
    if (list2 == null)  
        return list1;  
  
    ListNode res = new ListNode(0);  
    ListNode cur = res;  
  
    while (list1 != null && list2 != null) {  
        if (list1.val < list2.val) {  
            cur.next = list1;  
            list1 = list1.next;  
        } else {  
            cur.next = list2;  
            list2 = list2.next;  
        }  
        cur = cur.next;  
    }  
  
    if (list1 != null)  
        cur.next = list1;  
    if (list2 != null)  
        cur.next = list2;  
  
    return res.next;  
}

2. 线段最多重合问题

2.1 问题描述

在这里插入图片描述

下方的图片中, 重合最多的是 [4, 5], 这条线段压中了两条线段, 所以返回 2.
在这里插入图片描述

2.2 使用堆的方法做

解题之前我们首先要明确一点:任何一条重合区域的左边界, 都一定是某一条线段的左边界.
举例:比如 [1, 7], [2, 5] 重合区域的左边界一定是:2,
比如:[1, 7], [5, 13], 重合区域的左边界一定是:5.

在这里插入图片描述

2.2.1 逻辑实现

  1. 比如现在我们有:[1, 5], [3, 7], [2, 4], [1, 3], [2, 6], [5, 9],
  2. 然后将其按照左边界的大小(小的在前)排好序:[1, 5], [1, 3], [2, 4], [2, 6], [3, 7], [5, 9],
  3. 然后设置一个小根堆, 用来放置所有的线段的右边界.
  4. [1, 5] 的右边界放到堆中, 现在只有 [1, 5] 自己冲到 1 的左边界之后, 所以此时记为 1.
  5. 然后判断 [1, 3], 先判断小根堆中有没有小于 [1, 3]左边界 1 的数字, 要是有, 直接将其全部弹出, 因为要是堆中的右边界都到不了 1 这个左边界, 那就肯定是冲不进来. 肯定是不用考虑的. 但是这个 [1, 3] 没有上述情况, 所以将 3 放到堆中, 堆中现在有 3, 5. 此时代表有两条线段能到 1 这个左边界的位置:[1, 5] 和 [1, 3]. 所以此时记为 2.
  6. [2, 4] 加入到其中, 继续重复上述操作, 堆中没有比 2 小的, 堆中有:3, 4, 5 所以此时记为 3.
  7. 然后将 [2, 6] 加入到其中, 继续重复上述操作, 堆中没有比 2 小的, 堆中有:3, 4, 5, 6 所以此时记为 4.
  8. 然后将 [3, 7] 加入到其中, 继续重复上述操作, 堆中的 3, 4, 5, 63 <= 左边界3, 所以弹出堆中的 3, 因为此时 1, 3 已经对所有的线段没有意义了, 因为无论是以后的还是以前的线段, 都没有任何一个能和 [1, 3] 重合了, 因为我们最开始的时候已经排好序了, 不存在后续有好几个 [1, 2] 这样的情况. 此时现在堆中有:4, 5, 6, 7. 此时记为:4.
  9. 然后将 [5, 9] 放入其中, 堆中的 4, 5 <= 5, 所以将其弹出, 此时堆中有 6, 7, 9, 此时记为 3.
  10. 最后的答案是 4, 因为从开始到结束, 堆的大小经过了很多次变换, 但是我要的是其中最大的值.

总结:将所有的线段按照左边界排好序, 然后将开始的线段右边界的数字放到 堆中, 然后继续往下判断, 要是后来的线段的左边界比 堆中 含有的数字大, 就将堆较小的数字弹出, 最后遍历完了所有线段之后, 我们每次都对于堆中的数字进行了记录, 哪一次记录的数字最大就说明答案是几.

2.2.2 代码实例

为什么要设置一个 int[][], 因为我需要一个 N * 2 阶的矩阵, 此时需要一个对应的位置用来存放我的线段, 比如说: 我需要 3 个线段, 是: [2, 3], [3, 4], [2, 3], 所以对应的, 我需要这个矩阵存放, 反正线段是只有两个数字, 只要宽度是 2 就行了, 但是高度不一定, 因为我不知道自己需要几个线段, 所以需要用 n 来表示.

Arrays.sort(line, 0, n, (a, b) -> a[0] - b[0])
其中的 a 和 b 代表对应的数组本身, a[0] 和 b[0] 就代表数组中对应的数字.

在这里插入图片描述

ans = Math.max(ans, size) 这样设置的原因是:有可能先进去的线段已经被记为了 4, 但是后来进去的数组是有可能将堆中的数字弹出去很多, 此时已经被记为了 1, 所以我当然是要 4, 最后一定要返回 4.

// 测试链接 : https://www.nowcoder.com/practice/1ae8d0b6bb4e4bcdbf64ec491f63fc37
// 测试链接 : https://leetcode.cn/problems/meeting-rooms-ii/ 这个要会员才行.
// 请同学们务必参考如下代码中关于输入、输出的处理  
// 这是输入输出处理效率很高的写法  
// 提交以下的code,提交时请把类名改成"Main",可以直接通过  
  
import java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStreamReader;  
import java.io.OutputStreamWriter;  
import java.io.PrintWriter;  
import java.io.StreamTokenizer;  
import java.util.Arrays;  
import java.util.PriorityQueue;  
  
public class Code02_MaxCover {  
  
    public static int MAXN = 10001;  
  
    public static int[][] line = new int[MAXN][2];  
  
    public static int n;  
  
    public static void main(String[] args) throws IOException {  
       BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
       StreamTokenizer in = new StreamTokenizer(br);  
       PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));  
       while (in.nextToken() != StreamTokenizer.TT_EOF) {  
          n = (int) in.nval;  
          for (int i = 0; i < n; i++) {  
             in.nextToken();  
             line[i][0] = (int) in.nval;  
             in.nextToken();  
             line[i][1] = (int) in.nval;  
          }  
          out.println(compute());  
       }  
       out.flush();  
       out.close();  
       br.close();  
    }  
  
    public static int compute() {  
       // 堆的清空  
       size = 0;  
  
       // 线段一共有n条,line[0...n-1][2] : line[i][0] line[i][1], 左闭右闭  
       // 所有线段,根据开始位置排序,结束位置无所谓  
       // 比较器的用法  
       // line [0...n) 排序 : 所有小数组,开始位置谁小谁在前  
       Arrays.sort(line, 0, n, (a, b) -> a[0] - b[0]);  
       int ans = 0;  
       for (int i = 0; i < n; i++) {  
          // i : line[i][0] line[i][1]  
          while (size > 0 && heap[0] <= line[i][0]) {  
             pop();  
          }  
          add(line[i][1]);  
          ans = Math.max(ans, size);  
       }  
       return ans;  
    }  
  
    // 小根堆,堆顶0位置  
    public static int[] heap = new int[MAXN];  
  
    // 堆的大小  
    public static int size;  
  
    public static void add(int x) {  
       heap[size] = x;  
       int i = size++;  
       while (heap[i] < heap[(i - 1) / 2]) {  
          swap(i, (i - 1) / 2);  
          i = (i - 1) / 2;  
       }  
    }  
  
    public static void pop() {  
       swap(0, --size);   
       int i = 0, l = 1;  
       while (l < size) {  
          int best = l + 1 < size && heap[l + 1] < heap[l] ? l + 1 : l;  
          best = heap[best] < heap[i] ? best : i;  
          if (best == i) {  
             break;  
          }  
          swap(i, best);  
          i = best;  
          l = i * 2 + 1;  
       }  
    }  
  
    public static void swap(int i, int j) {  
       int tmp = heap[i];  
       heap[i] = heap[j];  
       heap[j] = tmp;  
    }  
  
    // 也找到了leetcode测试链接  
    // 测试链接 : https://leetcode.cn/problems/meeting-rooms-ii/    // 提交如下代码可以直接通过  
    public static int minMeetingRooms(int[][] meeting) {  
       int n = meeting.length;  
       Arrays.sort(meeting, (a, b) -> a[0] - b[0]);  
       PriorityQueue<Integer> heap = new PriorityQueue<>();  
       int ans = 0;  
       for (int i = 0; i < n; i++) {  
          while (!heap.isEmpty() && heap.peek() <= meeting[i][0]) {  
             heap.poll();  
          }  
          heap.add(meeting[i][1]);  
          ans = Math.max(ans, heap.size());  
       }  
       return ans;  
    }
}

2.2.3 复杂度分析

一共有 n 个线段.

时间复杂度:每一次将线段的右边界放到堆中, 最多就是进去一次, 然后出去一次, 一共有 n 条线段, 所以时间复杂度是:O(n * log(n)).

3. 累加和减半的最少操作次数

3.1 题目描述

在这里插入图片描述

3.2 逻辑实现

肯定是将所有的数字中最大的数字减少一半, 然后继续选择剩下的里最大的数字减少一半, 看看什么时候能将 sum 减小到 sum/2 以下.(同时需要注意:7 / 2 == 3.5, 这个0.5需要留着).

利用大根堆, 将所有的数字都放到大根堆中,

  1. 比如:arr[] = {20, 10, 100, 50}. 将这四个数字放入到大根堆中, 这样可以保证所有弹出来的数字肯定是数组中最大的.
  2. 然后将 100 拿出来, 减去 50,
  3. 然后将剩下的 50 放回到大根堆中, 现在大根堆中有 50, 50, 20, 10.
  4. 继续将大根堆中的根节点弹出, 还是 50, 减去一半, 将剩下的 25 放回到大根堆中, 现在大根堆中有 50, 25, 20, 10.
  5. 继续弹出, 这样周而复始, 最后直到累加和减少到了一半以下就停止.

3.3 代码实例

// 提交时把halveArray1改名为halveArray  
public static int halveArray1(int[] nums) {  
    // 大根堆  
    PriorityQueue<Double> heap = new PriorityQueue<>((a, b) -> b.compareTo(a));  
    double sum = 0;  
    for (int num : nums) {  
       heap.add((double) num);  
       sum += num;  
    }  
    // sum,整体累加和,-> 要减少的目标!  
    sum /= 2;  
    int ans = 0;  
    for (double minus = 0, cur; minus < sum; ans++, minus += cur) {  
       cur = heap.poll() / 2;  
       heap.add(cur);  
    }  
    return ans;  
}

3.4 复杂度分析

时间复杂度:O(n * log(n)).

证明:假设我们直接将所有位置的数字减少一半, 那么我需要遍历所有的数字, 然后进行减少一半的操作, 这样也能达成目标, 而且这个的操作次数是 n (相当于直接将所有的数字遍历一遍).

现在我将所有的数字放到大根堆中, 每一次都拿出最大的数字, 这样肯定是不会超过 n 个数字的. 每一次取出和放入的操作是:O(log(n)), 所以最后的时间复杂度是:O(n * log(n)).

3.5 优化之后的解法

double 类型的数字是有一个精度的, 要是精度太长了也是有可能出错了, 这个肯定都知道.

可以将所有的数字都乘以 2 的 20次方, 将 double类型的转换为 long类型的.(注意:这个问题还是不会变化, 和原来一样, 只要将这个新的数组的数字和降到原来的一般就行了).

int 类型转为:long 类型的是不会超出的. 因为 int类型是:32位, long是:64位.

这样的原理是:比如:arr[]数组中有一个数字是:5, 那我将 5 乘以 2 的 20 次方, 结果就是:
5 * 2 * 2 * 2 * 2 * 2 * 2 ... * 2, 所以我以后进行除二的时候, 就直接将 5后面的2 一个一个消除掉就行
相当于是给每一个数字都建立了一个缓冲区(哪怕是我除以十几次 2 也能是一个整数). 而且我自己也能进行控制, 要是 20 不够, 还可以乘以 30.

剩下的需要注意的地方都在注释中写好了, 主要是利用了自己写的函数, 速度是要比 JDK 自带的快很多的.

public static int MAXN = 100001;  
  
public static long[] heap = new long[MAXN];  
  
public static int size;  
  
// 提交时把halveArray2改名为halveArray  
public static int halveArray2(int[] nums) {  
    size = nums.length;   // 设置为数组长度.  
    long sum = 0;  
    for (int i = size - 1; i >= 0; i--) {  // 我们这里采用的是从底到顶建堆, 因为这样可以实现时间复杂度:O(n).  
       heap[i] = (long) nums[i] << 20;  // 在将其加入的时候给 数字 * 2的20次方,  
       sum += heap[i];  
       heapify(i);  
    }  
    sum /= 2;  
    int ans = 0;  
    for (long minus = 0; minus < sum; ans++) {  
       heap[0] /= 2;    // 这里将顶部的数字 / 2,       minus += heap[0]; // 然后将其加起来,  
       heapify(0);   // 最后还是将这个数字放回到堆中. 然后利用heapify函数重新建立好大根堆.  
    }   // 这个数字有可能已经比较小了, 毕竟减少了一半, 然后利用heapify函数将这个数字进行调整.  
    return ans;  
}  
  
public static void heapify(int i) {  
    int l = i * 2 + 1;  
    while (l < size) {  
       int best = l + 1 < size && heap[l + 1] > heap[l] ? l + 1 : l;  
       best = heap[best] > heap[i] ? best : i;  
       if (best == i) {  
          break;  
       }  
       swap(best, i);  
       i = best;  
       l = i * 2 + 1;  
    }  
}  
  
public static void swap(int i, int j) {  
    long tmp = heap[i];  
    heap[i] = heap[j];  
    heap[j] = tmp;  
}

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

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

相关文章

C++入门基础知识88(实例)——实例13【求一个数的阶乘】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于求一个数的阶乘的相关内容&#xff01; …

Oracle Data Guard备库清理归档脚本

1 说明 我们知道在Oracle Data Guard架构中归档模式是必须打开的&#xff0c;主库将日志传输到备库&#xff0c;最终存放到备库的归档日志文件中。随着系统的运行&#xff0c;归档日志文件会不断累积&#xff0c;如果不及时清理&#xff0c;则会造成归档空间被写满&#xff0c…

进程的那些事--实现shell

目录 前言 一、预备知识 二、实现步骤 1.思路 2.实现 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 学习的本质就是变现 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、预备知识 char * fgets ( char * str, i…

Qt开发技巧(十)新版随机数,模拟鼠标移动,QTextEdit卡死问题,函数返回值,参数结构化,选项卡控件,窗体属性

继续讲一些Qt开发中的技巧操作&#xff1a; 1.新版随机数 Qt中有自己的随机数取值方法&#xff0c;Qt5.10以前使用qsrand方法&#xff0c; Qt5.10以后提供了新的类 QRandomGenerator QRandomGenerator64 管理随机数&#xff0c;使用更方便&#xff0c;尤其是取某个区间的随机数…

【尚跑】2024铜川红色照金半程马拉松赛,大爬坡152安全完赛

1、赛事背景 2024年9月22日8点&#xff0c;2024铜川红色照金半程马拉松赛于照金1933广场鸣枪起跑&#xff01; 起跑仪式上&#xff0c;6000位选手们合唱《歌唱祖国》&#xff0c;熟悉的旋律响彻陕甘边革命根据地照金纪念馆前&#xff0c;激昂的歌声凝聚心中不变的热爱。随着国…

短视频矩阵系统源码图--示例

短视频矩阵系统源码通常指的是用于构建和管理短视频平台的一整套软件代码。这些代码包括了前端用户界面、后端服务器逻辑、数据库设计以及可能的移动应用客户端等部分。源码是软件的原始代码&#xff0c;开发者可以通过阅读和修改源码来定制或增强系统的功能。 开发短视频矩阵系…

第一弹:llama.cpp编译

1.编译llama.cpp命令行&#xff08;电脑版本&#xff09;&#xff1b; 2.交叉编译安卓命令行版本。 一、Llama.cpp是什么&#xff1f; 二、Llama.cpp编译 首先我们尝试编译llama.cpp. 2.1 下载llama.cpp 项目的github地址&#xff1a; https://github.com/ggerganov/llama…

PMP--二模--解题--151-160

文章目录 14.敏捷–流程&#xff1a;151、 [单选] 在每日站会上&#xff0c;项目负责人注意到一位资深开发人员正在将一些简单的待办事项重新分配给其他团队成员&#xff0c;理由是让资深开发人员处理复杂事项更有效率。项目负责人应该怎么做&#xff1f; 14.敏捷--通才型专家-…

0基础跟德姆(dom)一起学AI 机器学习01-机器学习概述

【知道】人工智能 - Artificial Intelligence 人工智能 - AI is the field that studies the synthesis and analysis of computational agents that act intelligently - AI is to use computers to analog and instead of human brain - 释义 - 仿智&#xff1b; 像人…

【多线程】多线程(4)(线程安全问题的原因,如何解决线程安全问题)

【线程安全问题的原因&#xff08;重点掌握&#xff09;】 1.线程在操作系统中:随机调度&#xff0c;抢占式执行&#xff08;核心原因&#xff09; 2.多个线程同时修改一个变量 3.修改操作「不是原子的」 4.内存可见性 5.指令重排列 &#xff08;后两个原因后面再谈&…

多元函数微分学基础题

这是基础题&#xff01;&#xff01;原则上必须要在第一轮初学并做完课后习题之后再做这个基础题&#xff0c;不能有错误&#xff08;马虎大意除外&#xff09;或无法解答。如有错误&#xff0c;该单元需要重学&#xff01;&#xff01; 多元函数微分学填空题 一、填空题 如…

基于SPI协议的Flash驱动控制

1、理论知识 SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外围设备接口&#xff09;通讯协议&#xff0c;是Motorola公司提出的一种同步串行接口技术&#xff0c;是一种高速、全双工、同步通信总线&#xff0c;在芯片中只占用四根管脚用来控制及数据传输&#…

关于Fake Location定位,运动世界校园问题

不好意思&#xff0c;之前那个文章其实是很早之前的&#xff0c;不知道为什么审核了很久一直没有通过&#xff0c;然后前几周莫名其妙点了一下重新发布&#xff0c;竟然发布成功了&#xff0c;这个方法已经失效了&#xff0c;要可以稳定&#xff0c;我建议是买一台root的手机&a…

Element-Plus中上传文件upload取消提示按钮与文字

去除提示按钮与文字 添加样式&#xff0c;让这个div进行隐藏 .el-upload__input {display: none !important; }

单片机长短按简单实现

单片机长短按简单实现 目录 单片机长短按简单实现1 原理2 示例代码2.1 按键实现 3 测试log4 其他实现方式 1 原理 按键检测和处理的步骤如下&#xff1a; 1&#xff1a;定时扫描按键&#xff08;使用定时器定时扫描&#xff0c;也可以用软件延时或者系统心跳之类的方式&#…

【动态规划-分组背包】力扣1981. 最小化目标值与所选元素的差

给你一个大小为 m x n 的整数矩阵 mat 和一个整数 target 。 从矩阵的 每一行 中选择一个整数&#xff0c;你的目标是 最小化 所有选中元素之 和 与目标值 target 的 绝对差 。 返回 最小的绝对差 。 a 和 b 两数字的 绝对差 是 a - b 的绝对值。 示例 1&#xff1a; 输入…

DAY17||654.最大二叉树 |617.合并二叉树 |700.二叉搜索树中的搜索 |

654.最大二叉树 题目&#xff1a;654. 最大二叉树 - 力扣&#xff08;LeetCode&#xff09; 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树…

物联网系统中TFT_LCD屏主流驱动方案详解

01 物联网系统中为什么要使用TFT-LCD驱动芯片 在物联网系统中使用TFT-LCD&#xff08;薄膜晶体管液晶显示器&#xff09;驱动芯片的原因主要可以归纳为以下几点&#xff1a; 专业性与高效性 1、专业图形处理&#xff1a;TFT-LCD驱动芯片内置了专业的图形处理引擎&#xff0…

全功能运营级开源跨境电商平台源码 —— 多语言全球化商城解决方案

实测分享【全功能运营级开源跨境电商平台】&#xff0c;它不仅默认集成了中英文双语系统&#xff0c;更内置了强大的翻译接口&#xff0c;支持自动翻译至全球133种语言&#xff0c;为商家打开通往世界的窗口。 核心特性亮点解析&#xff1a; 多语言自动翻译&#xff1a;该平台…

WEB 编程:富文本编辑器 Quill 配合 Pico.css 样式被影响的问题之还是 iframe

这个系列已经写了 3 篇了。这篇写如何使用 iframe 解决标题里面提到的问题。 前情提要 请看上一篇博文&#xff1a; WEB 编程&#xff1a;富文本编辑器 Quill 配合 Pico.css 样式被影响的问题之Shadow DOM WEB 编程&#xff1a;富文本编辑器 Quill 配合 Pico.css 样式被影响…