当前位置: 首页 > news >正文

前缀和 — 利用前缀信息解决子数组问题

【前缀和的核心思想是预先处理数组来快速计算任意子数组的和,基本上用于数组和序列问题。】

前缀和算法具体步骤
  1. 构造前缀和数组:

    • 给定一个数组nums,其前缀和数组prex定义为prex[i]表示为数组nums从起始位置到第i个位置的元素累加和。
    • 构建前缀和公式:

    p r e x [ i ] = n u m s [ i ] ( i = = 0 ) p r e x [ i ] = p r e x [ i − 1 ] + n u m s [ i ] ( i > 0 ) prex[i] = nums[i] \quad (i == 0) \\ \\ prex[i] = prex[i-1] + nums[i] \quad (i > 0) prex[i]=nums[i](i==0)prex[i]=prex[i1]+nums[i](i>0)

  2. 快速计算子数组和:

    • 一旦前缀和数组构建完成,就可以快速计算任意子数组nums[i...j]的元素累加和。

    s u m ( n u m s [ i . . . j ] ) = p r e x [ j ] − p r e x [ i − 1 ] ( i > 0 ) sum(nums[i...j]) = prex[j] - prex[i-1] \quad(i > 0) sum(nums[i...j])=prex[j]prex[i1](i>0)

    • i == 0时,子数组和也就是nums[0]

我们前面介绍过【滑动窗口算法】,滑动窗口算法也是基本用于数组和序列问题的,所以我们把【前缀和算法】与【滑动窗口算法】放在一起研究,也当作对滑动窗口算法的复习。

简要复习一下滑动窗口算法的步骤

【滑动窗口算法的核心思想就是维护一个固定长度的窗口,在数组或序列上滑动以满足某些条件。通常用于解决最大子数组和、最小子数组和等问题。】

  1. 初始化窗口:

    设置窗口的起始和结束指针。

  2. 滑动窗口:

    移动窗口的起始和结束指针,依据问题的要求调整窗口的大小,维护窗口的状态(例如窗口内元素的和,最大值,最小值等)。

[!TIP]

之前我们分析滑动窗口算法的时候就提到过,选择哪种数据结构来存储数据需要根据【窗口内的数据以及数据的处理形式】来考虑。

比如:

  • 如果需要记录窗口中各字符以及各字符出现的次数,就用哈希表。

我们通过一个例子看深入了解一下前缀和算法:

LeetCode560 和为 K 的子数组

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数

子数组是数组中元素的连续非空序列。

示例 1:

输入:nums = [1,1,1], k = 2
输出:2

示例 2:

输入:nums = [1,2,3], k = 3
输出:2

提示:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

暴力解法

既然是找满足条件的子数组个数,那我们可以枚举所有的子数组,然后选出符合条件的子数组就行了。

int subarraySum(vector<int> &nums, int k) {int size = nums.size();int result = 0;for (int left = 0; left < size; left++) {for (int right = left; right < size; right++) {//这个时候窗口为 nums[left...right]int sum = 0;int cur = left;while (cur <= right) {sum += nums[cur];cur++;}if (sum == k)result++;}}return result;
}

暴力解法就是这么通俗易懂,找出每个子串,然后对每个子串单独进行分析就行了。但是暴力解法找子串的时间复杂度是 O ( N 2 ) O(N^2) O(N2)​,时间复杂度太高了,所以我们需要思考另一种解法。

前缀和分析思路:

联想刚刚学到的前缀和表示子数组,我们知道,子数组nums[i...j]之和不就是prex[j] - prex[i-1]嘛。也就是说,和为 K 的子数组满足等式

p r e x [ j ] − p r e x [ i − 1 ] = = K prex[j] - prex[i-1] == K prex[j]prex[i1]==K

但是按照这个等式思路,我们只是利用了前缀和来方便找出各个子串的和罢了,还是要变动i,j两个变量来查找和为 K 的子数组,时间复杂度还是 O ( N 2 ) O(N^2) O(N2),我们得到目标是什么?是要降低时间复杂度。很容易想到,既然变动两个变量的时间复杂度为 O ( N 2 ) O(N^2) O(N2),那我们就试试只变动一个变量,我们对上面公式进行变换:

p r e x [ i − 1 ] = = p r e x [ j ] − K prex[i-1] == prex[j] - K prex[i1]==prex[j]K

从这个公式,我们清楚,如果子串最右边字符的位置j确定,那么要想找到【和为 K 的子数组】的个数,只需找到前缀和数组中0,1,...j-1这些位置对应的值中有几个值等于 K − p r e x [ j ] K-prex[j] Kprex[j], 如果我们把这个查找的实践复杂度降为 O ( 1 ) O(1) O(1),那么总体的时间复杂度只消耗在j的变动上了嘛,也就降为了 O ( N ) O(N) O(N)

怎么实现这个查找呢?和滑动窗口算法一样,面对不同的数据组织和变动情况,我们要选择合适的数据结构来帮助我们存储和查找数据。在这个题目中,因为要存储0,1,...,j-1的前缀和以及前缀和出现的次数,所以我们使用哈希表来存储数据,键代表j之前的各个前缀和,值代表此前缀和对应的数组出现的次数。

分析了这么多,最后我们只要移动j就行了,只需要对数组遍历一次。

我们给出前缀和解法:
int subarraySum(vector<int> &nums, int k) {//计数器,存储j之前数组和以及数组和出现的次数unordered_map<int,int> mp;mp[0]++; //数组为空,和自然为0int prex[nums.size()];int result = 0;for(int j = 0; j < nums.size(); j++){if(j == 0){prex[j] += nums[j];//查找j之前的数组和有几个满足条件if(mp.count(prex[j] - K)){result += mp[prex[j] - K];}mp[prex[j]]++;continue;}prex[j] = prex[j-1] + nums[j];if(mp.count(prex[j] - K)){result += mp[prex[j] - K];}mp[prex[j]]++;}return result;
}

这段代码便是我们利用【前缀和】和【哈希表】得到的解法,时间复杂度是降低了,空间复杂度能降低吗?

复盘这段代码,我们发现,在循环里,第'j'次循环只用到了prex[j]并不会用到前面的prex[0...j-1],所以我们不用再花费 O ( N ) O(N) O(N)的空间复杂度去维护前缀和数组prex[],直接用一个变量prex表示prex[j]即可。

改造后的代码:

int subarraySum(vector<int> &nums, int k) {//计数器,存储j之前数组和以及数组和出现的次数unordered_map<int,int> mp;mp[0]++; //数组为空,和自然为0int prex = 0;int result = 0;for(int num : nums){prex += num;if(mp.count(prex - K)){result += mp[prex - K];}mp[prex]++;}return result;
}

到这里,你基本上掌握了前缀和的思想了,但是要注意的是:

[!IMPORTANT]

前缀和只是我们用来表示子数组的一种方法而已,遇到具体问题,我们要找出问题的本质,子数组间有什么关系?最好能找出具体公式出来,比如这道【和为 K 的子数组】题目,我们就是找出了公式

p r e x [ j ] − p r e x [ i − 1 ] = = K prex[j] - prex[i-1] == K prex[j]prex[i1]==K

之后对这个公式进行分析,进行合适的变换。

1248 454

我们再看两道题来巩固一下【前缀和】与其他数据结构结合的算法思想

LeetCode523 连续的子数组

一个 好的子数组 是:

  • 长度 至少为 2 ,且
  • 子数组元素总和为 k 的倍数。

注意

  • 子数组 是数组中 连续 的部分。
  • 如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称 xk 的一个倍数。0 始终 视为 k 的一个倍数。

示例 1:

输入:nums = [23,2,4,6,7], k = 6
输出:true
解释:[2,4] 是一个大小为 2 的子数组,并且和为 6 。

示例 2:

输入:nums = [23,2,6,4,7], k = 6
输出:true
解释:[23, 2, 6, 4, 7] 是大小为 5 的子数组,并且和为 42 。
42 是 6 的倍数,因为 42 = 7 * 6 且 7 是一个整数。

示例 3:

输入:nums = [23,2,6,4,7], k = 13
输出:false

提示:

  • 1 <= nums.length <= 105
  • 0 <= nums[i] <= 1^09
  • 0 <= sum(nums[i]) <= 2^31 - 1
  • 1 <= k <= 2^31 - 1

分析过程:

这道题算是【和为 K 的子数组】的变式,求【和为 K 的整数倍的子数组】,我们先考虑迁移【和为 K 的子数组的解法】。

得出公式:

p r e x [ j ] − p r e x [ i − 1 ] = = λ ∗ K p r e x [ i − 1 ] = = p r e x [ j ] − λ ∗ K prex[j] - prex[i-1] == λ*K \\ prex[i-1] ==prex[j] - λ*K prex[j]prex[i1]==λKprex[i1]==prex[j]λK

解法框架如下:

bool checkSubarraySum(vector<int> &nums, int k) {//计数器,存储j之前数组和以及数组和出现的次数unordered_map<int,int> mp;mp[0]++; //数组为空,和自然为0int prex = 0;int result = 0;for(int num : nums){prex += num;if(mp.count(prex - lamda*K)){result += mp[prex - lamda*K];}mp[prex]++;}return result > 0;
}

我们怎么确定这个 l a m d a lamda lamda呢?要枚举 l a m d a lamda lamda的取值并代入吗? l a m d a lamda lamda取值为 0 , . . . , [ p r e x / X ] 0,...,[prex/X] 0,...,[prex/X]。或者遍历mp里的每个键,查看prex是否能整除X

上面的分析只分析了子数组的数组和可能为 K 的倍数,子数组的长度至少为 2,这个要求我们并没有考虑。和子数组长度有关的话,哈希表存储前缀和以及前缀和出现的次数就不能用了,因为哈希表里的前缀和nums[0...i]并不能确定是i是什么,我们只是将前缀和的值一股脑放进哈希表里而已。

所以我们现在要改变数据存储形式,要么使用别的数据结构,要么将哈希表里的键值对对应的数据改为其他数据。所以现在,我们要体现出【前缀和】,以及【前缀和对应的位置nums[0...i](i)】和【出现的次数】。怎么体现呢?按照之前思路,我们是在遍历prex[j],在遍历的同时,将{前缀和:{位置,出现次数}}存入哈希表中。

解法如下:

bool checkSubarraySum(vector<int> &nums, int k) {//计数器,存储j之前数组和以及数组和出现的次数unordered_map<int,pair<int,int>> mp;mp[0] = {-1,1}; //数组为空,和自然为0int prex = 0;int result = 0;for(int j = 0;j < nums.size();j++){prex += nums[j];//遍历哈希表,查看是否存在这样一个前缀和,使得prex与这个前缀和之差是K的倍数,且满足长度大于等于2for(const auto& element : mp){if((prex - element.first)% k == 0){if(element.second.first < j - 1){result += element.second.second;}}}mp[prex] = {j,mp[prex]+1}; //?}return result > 0;
}

接下来看看二维以及多维的前缀和是如何使用的

二维前缀和

【二维前缀和】和【一维前缀和】一样,也是记录前面数组元素的累加和。对于一维而言,就是前 0 , 1 , . . . , i − 1 0,1,...,i-1 0,1,...,i1这些位置对应的元素的累加和,二维也是一样,前 0 < = m < i , 0 < = n < j , ( m , n ) 0 <= m < i, 0 <= n < j,(m,n) 0<=m<i,0<=n<j,(m,n) 这些位置对应的元素累加和,其实也就是以 ( i , j ) (i,j) (i,j)​ 为右下角的正方形左上方的所有元素之和。同样,我们给出二维前缀和数组以及递推公式:

二维前缀和具体步骤
  1. 构建二维前缀和数组

    • 给定一个二维数组matrix,其前缀和数组定义为preSum[i][j]表示以(0,0)为左上角,(i,j)为右下角的矩形内所有元素之和。
    • 构建二维前缀和公式:

    p r e S u m [ 0 ] [ 0 ] = m a t r i x [ 0 ] [ 0 ] p r e S u m [ 0 ] [ j ] = p r e S u m [ 0 ] [ j − 1 ] + m a t r i x [ 0 ] [ j ] ( i = = 0 , j > 0 ) p r e S u m [ i ] [ 0 ] = p r e S u m [ i − 1 ] [ 0 ] + m a t r i x [ i ] [ 0 ] ( i > 0 , j = = 0 ) p r e S u m [ i ] [ j ] = p r e S u m [ i − 1 ] [ j ] + p r e S u m [ i ] [ j − 1 ] − p r e S u m [ i − 1 ] [ j − 1 ] + m a t r i x [ i ] [ j ] ( i > 0 , j > 0 ) preSum[0][0] = matrix[0][0] \\ preSum[0][j] = preSum[0][j-1] + matrix[0][j]\quad(i == 0, j > 0)\\ preSum[i][0] = preSum[i-1][0] + matrix[i][0]\quad(i>0,j==0)\\ preSum[i][j] = preSum[i-1][j] + preSum[i][j-1] - preSum[i-1][j-1] + matrix[i][j]\quad(i>0,j>0) preSum[0][0]=matrix[0][0]preSum[0][j]=preSum[0][j1]+matrix[0][j](i==0,j>0)preSum[i][0]=preSum[i1][0]+matrix[i][0](i>0,j==0)preSum[i][j]=preSum[i1][j]+preSum[i][j1]preSum[i1][j1]+matrix[i][j](i>0,j>0)

  2. 优化后的二维前缀和数组

    我们发现,上面的二维前缀和公式过于麻烦,需要分类讨论四种情况,这四种情况都是边界处的情况。所以我们现在弱化边界,在边界之外再套一层,在原来的二维数组左上方套一层,套上的每一个元素都是 0,这样就不会影响前缀和数组的数值。

    • 优化后的数组定义:preSum[i][j]表示以(0,0)为左上角,(i-1,j-1)为右下角的矩形内所有元素之和。preSum[0][0...n],preSum[0...n][0]这些元素都赋值 0,这也就是我们上面说的套上一层辅助数据,这些数据都是 0。
    • 二维前缀和公式:

    p r e S u m [ i ] [ j ] = p r e S u m [ i − 1 ] [ j ] + p r e S u m [ i ] [ j − 1 ] − p r e S u m [ i − 1 ] [ j − 1 ] + m a t r i x [ i − 1 ] [ j − 1 ] ( i > = 1 , j > = 1 ) preSum[i][j] = preSum[i-1][j] + preSum[i][j-1] - preSum[i-1][j-1] + matrix[i-1][j-1]\quad(i>=1,j>=1) preSum[i][j]=preSum[i1][j]+preSum[i][j1]preSum[i1][j1]+matrix[i1][j1](i>=1,j>=1)

    优化后的数组,preSum[i][j]对应matrix[i-1][j-1]为右下角的矩形元素累加和。

  3. 快速计算区域子矩阵和(多维数组叫着有点别扭,后面都会用矩阵代替多维数组)

    得出前缀和矩阵后,我们可以利用前缀和矩阵快速计算出子矩阵中元素累加和。如果子矩阵的左上角为(m,n),右下角为(i,j),那么我们可以直接利用公式:

    S u b M a t r i x S u m = p r e S u m [ i ] [ j ] − p r e S u m [ i ] [ n − 1 ] − p r e S u m [ m − 1 ] [ j ] + p r e S u m [ m − 1 ] [ n − 1 ] SubMatrixSum = preSum[i][j] - preSum[i][n-1] - preSum[m-1][j] + preSum[m-1][n-1] SubMatrixSum=preSum[i][j]preSum[i][n1]preSum[m1][j]+preSum[m1][n1]

    这里是利用了优化后的前缀和数组来进行分析,i,j的取值为 1... n 1...n 1...n

我们来看一道题目,充分理解二维前缀和

LeetCode1314 矩阵区域和

给你一个 m x n 的矩阵 mat 和一个整数 k ,请你返回一个矩阵 answer ,其中每个 answer[i][j] 是所有满足下述条件的元素 mat[r][c] 的和:

  • i - k <= r <= i + k,
  • j - k <= c <= j + k
  • (r, c) 在矩阵内。

示例 1:

输入:mat = [[1,2,3],[4,5,6],[7,8,9]], k = 1
输出:[[12,21,16],[27,45,33],[24,39,28]]

示例 2:

输入:mat = [[1,2,3],[4,5,6],[7,8,9]], k = 2
输出:[[45,45,45],[45,45,45],[45,45,45]]

提示:

  • m == mat.length
  • n == mat[i].length
  • 1 <= m, n, k <= 100
  • 1 <= mat[i][j] <= 100

问题分析:

我们很容易看出,answer[i][j]表示的就是以[i][j]为中心,边长为 2 ∗ k + 1 2*k+1 2k+1的正方形内的所有元素之和。对照刚刚讲的二维前缀矩阵,这个正方形可以由什么表示呢?

int start_i = std::max(i-k,0);
int start_j = std::max(j-k,0);
int end_i = std::min(m-1,i+k);
int end_j = std::min(n-1,j+k);

其实这个“正方形”中的元素就是以start_i,start_j为左上角,end_i,end_j为右下角的矩形中的所有元素。answer[i][j]存的就是这个矩形中所有元素的累加和嘛。这个累加和我们直接用递推公式就可以得出来:

S u b M a t r i x S u m = p r e S u m [ e n d i + 1 ] [ e n d j + 1 ] − p r e S u m [ e n d i + 1 ] [ s t a r t j − 1 + 1 ] − p r e S u m [ s t a r t i − 1 + 1 ] [ e n d j + 1 ] + p r e S u m [ s t a r t i − 1 + 1 ] [ s t a r t j − 1 + 1 ] SubMatrixSum = preSum[end_i+1][end_j+1] - preSum[end_i+1][start_j-1+1] \\ - preSum[start_i-1+1][end_j+1] + preSum[start_i-1+1][start_j-1+1] SubMatrixSum=preSum[endi+1][endj+1]preSum[endi+1][startj1+1]preSum[starti1+1][endj+1]+preSum[starti1+1][startj1+1]

这里的(i,j)是基于原矩阵matrix的。

现在我们给出最终代码:

vector <vector<int>> matrixBlockSum(vector <vector<int>> &mat, int k) {int m = mat.size();int n = mat[0].size();vector <vector<int>> answer(m, vector<int>(n));//创建前缀和矩阵int preSum[m + 1][n + 1];for (int j = 0; j <= n; j++) {preSum[0][j] = 0;}for (int i = 0; i <= m; i++) {preSum[i][0] = 0;}//为前缀和矩阵赋值for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {preSum[i + 1][j + 1] = preSum[i][j + 1] + preSum[i + 1][j]- preSum[i][j] + mat[i][j];}}//为answer矩阵赋值for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {int start_i = std::max(i-k,0);int start_j = std::max(j-k,0);int end_i = std::min(m-1,i+k);int end_j = std::min(n-1,j+k);answer[i][j] = preSum[end_i + 1][end_j + 1] - preSum[end_i + 1][start_j]- preSum[start_i][end_j + 1] + preSum[start_i][start_j];}}return answer;
}

注意!!!,前缀和只是一种求子数组和子矩阵的方法而已,当遇到需要求解子数组或者子矩阵的问题时,如果需要用到子数组或者子矩阵中的元素,可以使用前缀和来表示子数组或者子矩阵。

相关文章:

前缀和 — 利用前缀信息解决子数组问题

【前缀和的核心思想是预先处理数组来快速计算任意子数组的和&#xff0c;基本上用于数组和序列问题。】 前缀和算法具体步骤 构造前缀和数组&#xff1a; 给定一个数组nums&#xff0c;其前缀和数组prex定义为prex[i]表示为数组nums从起始位置到第i个位置的元素累加和。构建前…...

2024年最新版Ajax+Axios 学习【包含原理、Promise、报文、接口等...】

基础知识 AJAX概念 AJAX概念&#xff1a;是浏览器与服务器进行数据通信的技术。 认识URL 定义&#xff1a;统一资源定位符&#xff0c;简称网址&#xff0c;用于访问网络上的资源。 组成&#xff1a; http协议&#xff1a;超文本传输协议&#xff0c;规定浏览器和服务器之…...

【Qt线程】—— Qt线程详解

目录 &#xff08;一&#xff09;多线程的概述 &#xff08;二&#xff09;Qt线程的使用条件 &#xff08;三&#xff09;创建线程的方法 3.1 继承QTread&#xff0c;重写run()函数 3.1.1 为什么要重写 3.2 继承QObject 3.3 核心API介绍 3.4 关闭线程的使用方法 &…...

Golang | Leetcode Golang题解之第391题完美矩形

题目&#xff1a; 题解&#xff1a; func isRectangleCover(rectangles [][]int) bool {type point struct{ x, y int }area, minX, minY, maxX, maxY : 0, rectangles[0][0], rectangles[0][1], rectangles[0][2], rectangles[0][3]cnt : map[point]int{}for _, rect : range…...

〖open-mmlab: MMDetection〗解析文件:mmdet/models/detectors/two_stage.py

目录 MMDetection中的两阶段检测器&#xff1a;深入解析two_stage.py源码两阶段检测器概述two_stage.py的关键组件类定义和初始化构造函数Neck头配置RPN头配置RoI头配置_load_from_state_dict方法概述参数解释代码解析 特征提取方法签名文档字符串&#xff08;Docstring&#x…...

【最新华为OD机试E卷-支持在线评测】机器人活动区域(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,…...

C语言:刷题日志(1)

一.阶乘计算升级版 本题要求实现一个打印非负整数阶乘的函数。 其中n是用户传入的参数&#xff0c;其值不超过1000。如果n是非负整数&#xff0c;则该函数必须在一行中打印出n!的值&#xff0c;否则打印“Invalid input”。 首先&#xff0c;知道阶乘是所有小于及等于该数的…...

ios私钥证书(p12)导入失败,Windows OpenSSl 1.1.1 下载

ios私钥证书(p12)导入失败 如果你用的OpenSSL版本是v3那么恭喜你V3必然报这个错&#xff0c;解决办法将OpenSSL 3降低成 v1。 Windows OpenSSl 1.1.1 下载 阿里云网盘下载地址&#xff1a;OpenSSL V1...

嵌入式面试经典30问:二

1. 嵌入式系统中&#xff0c;如何选择合适的微控制器或微处理器&#xff1f; 在嵌入式系统中选择合适的微控制器&#xff08;MCU&#xff09;或微处理器&#xff08;MPU&#xff09;时&#xff0c;需要考虑多个因素以确保所选组件能够满足项目的具体需求。以下是一些关键步骤和…...

目标检测-YOLOv1

YOLOv1介绍 YOLOv1&#xff08;You Only Look Once version 1&#xff09;是一种用于目标检测的深度学习算法&#xff0c;由Joseph Redmon等人于2016年提出。它基于单个卷积神经网络&#xff0c;将目标检测任务转化为一个回归问题&#xff0c;通过在图像上划分网格并预测每个网…...

python基础语法八-异常

书接上回&#xff1a; python基础语法一-基本数据类型 python基础语法二-多维数据类型 python基础语法三-类 python基础语法四-数据可视化 python基础语法五-函数 python基础语法六-正则匹配 python基础语法七-openpyxl操作excel 1. 异常简介 (1)异常&#xff1a;遇到…...

【堆的应用--C语言版】

前面一节我们都已将堆的结构&#xff08;顺序存储&#xff09;已经实现&#xff0c;对树的相关概念以及知识做了一定的了解。其中我们在实现删除操作和插入操作的时候&#xff0c;我们还同时实现了建大堆&#xff08;小堆&#xff09;的向上&#xff08;下&#xff09;调整算法…...

【微信小程序】搭建项目步骤 + 引入Tdesign UI

目录 创建1个空文件夹&#xff0c;选择下图基础模板 开启/支持sass 创建公共style文件并引入 引入Tdesign UI: 1. 初始化&#xff1a; 2. 安装后&#xff0c;开发工具进行构建&#xff1a; 3. 修改 app.json 4. 使用 5. 自定义主题色 创建1个空文件夹&#xff0c;选择下…...

android系统源码12 修改默认桌面壁纸--SRO方式

1、aosp12修改默认桌面壁纸 代码路径 &#xff1a;frameworks\base\core\res\res\drawable-nodpi 替换成自己的图片即可&#xff0c;不过需要覆盖所有目录下的图片。 由于是静态修改&#xff0c;则需要make一下&#xff0c;重新编译。 2、方法二Overlay方式 由于上述方法有…...

Echarts可视化

echarts是一个基于javascripts的开源可视化图表库 画图步骤&#xff1a; 1.引入echarts.js文件 <script src" https://cdn.jsdelivr.net/npm/echarts5.5.1/dist/echarts.min.js"></script> 也可将文件下载到本地通过src引入。 2. 准备一个呈现图表的…...

验证linux gpu是否可用

通过torch验证 import torchprint(torch.__version__) # 查看torch当前版本号 print(torch.version.cuda) # 编译当前版本的torch使用的cuda版本号 print(torch.cuda.is_available()) # 查看当前cuda是否可用于当前版本的Torch&#xff0c;如果输出True&#xff0c;则表示可…...

JavaScript( 简介)

目录 含义 实例 js代码位置 1 外部引入js文件 2 在 HTML 中&#xff0c;JavaScript 代码必须位于 标签之间。 小结 含义 js是一门脚本语言&#xff0c;能够改变HTML内容 实例 getElementById() 是多个 JavaScript HTML 方法之一。 本例使用该方法来“查找” id"d…...

Linux中的编译器gcc/g++

目录 一、gcc与g的区别 1.gcc编译器使用 2.g编译器使用 二、gcc/g编译器编译源文件过程 1.预处理 2.编译 3.汇编 4.链接 三、静态库和动态库 1.库中的头文件作用 2.静态库 3.动态库 四、gcc编译器的一些选项命令 一、gcc与g的区别 gcc用于编译C语言代码&#xff…...

RK3568安装部署Docker容器

设置华为镜像源 sudo sed -i s/huaweicloud.com/ustc.edu.cn/g /etc/apt/sources.list更新索引 rootok3568:/home/forlinx# sudo apt-get update Hit:1 http://ports.ubuntu.com/ubuntu-ports focal InRelease Hit:2 http://ports.ubuntu.com/ubuntu-ports focal-updates InR…...

Ubuntu 常用指令和作用解析

Ubuntu 常用指令和作用解析 Ubuntu 是一种常见的 Linux 发行版&#xff0c;它利用了 Unix 的力量和开源软件的精神。掌握常用指令可以提高我们在使用 Ubuntu 时的效率。本文将介绍一些常见的指令及其用途。 目录 更新与安装软件文件与目录操作系统信息与资源监控用户与权限管…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...