【LeetCode滑动窗口专题】水果成篮 + 最小覆盖子串(hard)+ 字符串的排列
二刷刷到滑动窗口,发现有一些细节和遗漏,在此补充
实际上关于滑动窗口的题还有一题:最小长度的子数组
进入正题
水果成篮
LeetCode904水果成篮
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。
示例 1:
输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。
示例 2:
输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。
示例 3:
输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。
思路
题目的要求,换个说法就是:找到一段数组中的元素,该段元素中类型最多为2种,如果段中元素达到3种就直接停止。我们的目标是使这个段中元素的个数尽可能多
例如:(示例3)
[[1,2],3,2,2]
[[1,2,3],2,2]
如果是从1开始取的话,到3就会停止,最终只能取到[1, 2],显然这不是题设规则下的最优解
如果我们从2开始取呢?
[1,[2,3],2,2]
[1,[2,3,2],2]
[1,[2,3,2,2]]
最后结果是[2,3,2,2],这是最优解
这里的“段”,实际上很类似窗口,由此可以联想到滑动窗口算法
我们需要维护的窗口内只能存在两种类型的数,一旦出现第三种,缩小窗口的左边界,直到再次满足条件后,继续使右边界扩大
思路很明确了,那怎么实现呢?关键点是如何记录元素出现次数
根据之前的经验,要记录某种东西出现的次数,可以考虑用哈希表
这里创建一个哈希表unordered_map,键是当前的遍历值,值是出现次数
判断哈希表的大小,一旦大于2,就触发循环,在map中找到以左指针指向的数组值为哈希表键的元素,将其移除即可(注意,要先删除干净其键对应的值,这里在下面细说),同时,left的指针向右移动。
最后,左右指针作差,更新结果保存变量(取最大的保存)
代码
坑(关于map的使用)
思路定下来了,写代码吧
这是根据思路写的第一版
class Solution {
public:
int totalFruit(vector<int>& fruits) {
//定义左指针
int left = 0;
int res = 0;
unordered_map<int, int> typeCount;//定义一个哈希表,键是遍历值
for(int right = 0; right < fruits.size(); ++right){
typeCount[fruits[right]]++;
while(typeCount.size() > 2){//如果类型大于2,开始移动左指针缩小窗口
auto it = typeCount.find(fruits[left]);
if(it != typeCount.end()){//找到左指针对应的键值,删除
typeCount.erase(it);
}
left++;
}
res = max(res, right - left + 1);
}
return res;
}
};
看起来没有什么问题,其实问题挺大的,并且很隐蔽
问题主要出现在以下部分:
auto it = typeCount.find(fruits[left]);
if(it != typeCount.end()){//找到左指针对应的键值,删除
typeCount.erase(it);
}
这里的本意是:在map中找到以fruits[left]
为键的元素,然后将其移除。
这是符合我们之前的逻辑推导的,但是在代码落实的时候出问题了
在map中查找某个键对应的值,返回的是一个迭代体,我们可以通过it != typeCount.end()
判断是否查找到对应的键值
这里在找到键值对后,我直接把返回的迭代体删了
只删迭代体对象没用啊,map中对应的键值对是不受影响的,也就是说,删了个寂寞
正确删除map中键值对的操作是:
- 使用find找到键值对
- 将键对应的值(it->second)全部删除
- 判断当前键对应的值为0后,删除指向键值对的迭代体
完整代码
根据上述讨论修改后的代码如下:
class Solution {
public:
int totalFruit(vector<int>& fruits) {
int left = 0;//定义左指针
int res = 0;
unordered_map<int, int> typeCount;//定义一个哈希表,键是遍历值
for(int right = 0; right < fruits.size(); ++right){
typeCount[fruits[right]]++;//记录出现次数
while(typeCount.size() > 2){//如果类型大于2,开始移动左指针缩小窗口
auto it = typeCount.find(fruits[left]);//使用find找到键值对,并返回迭代体对象
it->second--;//将键对应的值全部删除
if(it->second == 0){
typeCount.erase(it); //删除指向键值对的迭代体
}
left++;//左指针右移
}
res = max(res, right - left + 1);//将最大值更新到结果变量
}
return res;
}
};
本题思路其实不难想,主要问题出现在代码实现,对于map的使用不熟练
最小覆盖子串
LeetCode76最小覆盖子串
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
示例 2:
输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。
示例 3:
输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
思路
大体思路
从题目给的模板(minWindow)可以得到提示,这题可以用滑动窗口算法解(其实不看也应该能想到)
我们需要维护一个窗口
窗口的右边界不断遍历输入字符串s,往窗口内添加字符,直到当前窗口内出现目标字符串t中的所有字符,此时移动左边界来缩小窗口,取出冗余字符
好了,此题关于滑动窗口部分的思路讨论完毕
很清晰是吧?然后写代码的时候会发现根本写不出
因为很多思路中理所当然的地方用代码很难实现
代码实现思路
那么用代码写的时候应该怎么考虑呢?
我们要维护两个哈希表(unordered_map),hs和ht
ht用于统计目标字符串t中各字符出现的次数;
hs用于记录当前遍历字符出现的次数;(至于为什么是“次数”,后面会说)
定义结果字符串res、左指针变量left、计数变量count
右指针遍历输入字符串s,将遍历字符加入hs
如果当前遍历字符是目标字符串t中的目标字符,且出现次数小于等于ht中的出现次数,计数变量加1
代码实现中,记录当前遍历字符出现的次数是为了判断是否包含字符串t中所有的字符。
具体来说,算法维护两个哈希表:ht和hs,分别表示字符串t和当前窗口内的字符串s中每个字符的出现次数。
当扫描到一个新的字符时,程序会检查该字符是否在ht中出现。如果出现,就将hs中对应的计数器加1,并判断是否小于等于ht中的计数器。如果小于等于,说明该字符是目标字符之一,并且当前窗口内仍然存在未满足条件的目标字符,因此 count 计数器加1。
通过统计s中目标字符出现的次数,可以判断当前窗口内是否包含t中的所有字符。当count计数与t长度相等时表示当前窗口中已经包含有全部t中的目标字符,需要更新结果字符串res。
因此,记录遍历字符出现的次数在这个算法中起到至关重要的作用,它帮助我们确定了窗口内目标字符的数量,从而实现了正确的滑动窗口匹配。
首先,需要定义一堆变量
class Solution {//输入:s = "ADOBECODEBANC", t = "ABC"
public:
string minWindow(string s, string t) {
unordered_map<char, int>hash4s, hash4t;//用于统计s和t的hash表,键为对应字符,值为出现次数
int left = 0;
string res;//定义结果字符串
int count = 0;//用于统计s中目标字符(t中字符)出现的次数
...
}
然后我们遍历字符串t,将其中的字符出现次数统计到hash4t中
class Solution {
public:
string minWindow(string s, string t) {
...
for(int i = 0; i < t.size(); ++i){//统计t的字符出现次数
hash4t[t[i]]++;
}
}
接下来开始遍历字符串s,将遍历到的元素统计到hash4s中,然后我们去hash4t中找当前hash4s中被记录的元素是否出现过
目的是为了看当前元素是不是目标元素,如果是目标元素,并且该元素在s中出现的次数少于t中出现的次数时,那么我们认为找到了一个有效的目标字符
class Solution {
public:
string minWindow(string s, string t) {
...
for(int i = 0; i < t.size(); ++i){//统计t的字符出现次数
hash4t[t[i]]++;
}
for(int right = 0; right < s.size(); ++right){//遍历字符串s,对应字符出现后在hash4s记录
hash4s[s[right]]++;
if(hash4s[s[right]] <= hash4t[s[right]]){
count++;//计数+1
}
}
}
这里需要特别解释一下(关于代码实现)
1、实际上hash4t在一开始的时候大小为3,为什么还能一直与大于3位置的元素进行比较
举个例子,我们一开始统计完t的元素后,hash4t={'A': 1, 'B': 1, 'C': 1}。
然后我们开始遍历s,第一次得到A,A在s中出现一次,在t中也出现一次,这是一个有效的目标字符,因此计数加1
第二次遍历s得到D,而D在t中是没有的,在hash4t中也没有,D不是目标字符,但因为进行了比较,所以hash4t中也要生成一个关于D的记录,此时hash4t={'A': 1, 'B': 1, 'C': 1, 'D': 0}
结论就是:哈希表会给不存在的键值一个默认值
继续
在遍历s的过程中,if条件不断被触发,当我们的窗口内收集到了3个目标字符(ADOBEC),此时count = 3
因为已经收集到3个有效的目标字符,所以我们要对当前子串进行保存
class Solution {
public:
string minWindow(string s, string t) {
...
for(int i = 0; i < t.size(); ++i){//统计t的字符出现次数
hash4t[t[i]]++;
}
for(int right = 0; right < s.size(); ++right){//遍历字符串s,对应字符出现后在hash4s记录
hash4s[s[right]]++;
if(hash4s[s[right]] <= hash4t[s[right]]){
count++;//计数+1
}
while(hash4s[s[left]] > hash4t[s[left]]){//此时,要移动左边界去除当前窗口中的冗余字符
//注意,是先减值,再移动left!!!!
hash4s[s[left]]--;//对应减少hs中的值,直到hs中的目标字符出现次数均与ht中相等
left++;//移动左边界
}
if(count == t.size()){//找到3个有效目标字符
if(res.empty() || right - left + 1 < res.size()){
res = s.substr(left, right - left + 1);//截取当前窗口内字符串作为结果字符串
}
}
}
}
关键点!!!!!!!!
按理来说应该开始缩小窗口的左边界,但是如果现在马上缩的话,当前子串中目标字符的数量就会又不满足3个了,我们可能会因此漏掉某些情况或者需要进行多余的处理
比如如果变量到ADOBEC立刻缩小左边界,那么此时窗口内为DOBEC,没凑齐目标字符,因此右边界继续移动
当移动到DOBECODEB时,B出现了2次,此时仍然没有凑齐目标字符
再往后移动到了DOBECODEBA,终于又凑齐3个目标字符,但是该子串长于第一次找到的子串因此不更新,此时缩小左边界
缩到CODEBA,继续缩ODEBA,不满足了,右边界继续移动直到ODEBANC又再次满足
然后是缩小左边界,缩到ANC不满足条件,但是因为s已经遍历完成,因此我们需要回退到上一个满足条件的位置即BANC,期间我们要需要比较其是否为目前找到的最小子串,最后返回结果
根据上面的分析,如果我们立刻进行缩窗操作,最后也是可以得到结果的,但是需要进行更多的逻辑控制
因此我们选择先不缩小窗口,继续遍历
那么还是跟前面一样,遇到目标字符,并且目标字符在s中出现的次数小于t中的次数(有效目标字符),count就加1
否则就在hash4t中创建一个默认值,这样做你会发现当遍历到ADOBECODEB时,B已经出现了两次而我们还没有对其进行处理
先别急,继续遍历到ADOBECODEBA,OK此时我们要进行缩窗操作
class Solution {
public:
string minWindow(string s, string t) {
...
for(int i = 0; i < t.size(); ++i){//统计t的字符出现次数
hash4t[t[i]]++;
}
for(int right = 0; right < s.size(); ++right){//遍历字符串s,对应字符出现后在hash4s记录
hash4s[s[right]]++;
if(hash4s[s[right]] <= hash4t[s[right]]){
count++;//计数+1
}
while(hash4s[s[left]] > hash4t[s[left]]){//此时,要移动左边界去除当前窗口中的冗余字符
//注意,是先减值,再移动left!!!!
hash4s[s[left]]--;//对应减少hs中的值,直到hs中的目标字符出现次数均与ht中相等
left++;//移动左边界
}
}
}
注意我们缩小左边界时的逻辑,下面以实例来说明
遍历到ADOBECODEBA时,此时
hash4t={'A': 1, 'B': 1, 'C': 1,'D': 0, 'O': 0, 'E': 0}
hash4s={'A': 2, 'B': 2, 'C': 1,'D': 1, 'O': 2, 'E': 2}
那么此时hash4s[s[left]] > hash4t[s[left]]这个条件会一直满足,因此s[left]在hash4s中的值会对应的被减少
同时left指针也不断往右移动,缩小窗口,最终left来到第二个B的位置,此时while循环的条件无法满足,跳出循环
ADOBECODEBANC
↑
left
此时hash4s={'A': 1, 'B': 1, 'C': 0,'D': 0, 'O': 0, 'E': 0}
当前子串由于缺少C还不满足条件,且s还没有遍历完,因此right指针继续向右遍历s
当s遍历完成,C正好也获取到了,并且此时的子串也是长度最小的一个,返回结果即可
还要注意的一点是关于count的
其实我们可能会有一个惯性,认为只要count=3就必须更新子串,其实不是,虽然每次我们都触发count=3的if条件,但是如果当前子串的长度没有之前的小,也是不会更新最小子串的
也就是说,肯会有很多个满足条件的子串,但我们只保存最小的
完整代码
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char, int> hash4t, hash4s;
int left = 0;
int count = 0;
string res;
for(int i = 0; i < t.size(); ++i){//统计t的字符出现次数
hash4t[t[i]]++;
}
//遍历字符串s
for(int right = 0; right < s.size(); ++right){
hash4s[s[right]]++;//标记出现过的元素
if(hash4s[s[right]] <= hash4t[s[right]]){//如果当前字符为有效目标字符,计数加1
count++;
}
//处理窗口左边界
while(hash4s[s[left]] > hash4t[s[left]]){
hash4s[s[left]]--;//对应计数值减减
left++;//窗口左边界右移
}
//处理收集到3个有效目标字符时的情况
if(count == t.size()){
if(res.empty() || right - left + 1 < res.size()){//保存最小的子串
res = s.substr(left, right - left + 1);
}
}
}
return res;
}
};
再提供一个Python版的方便忘了的时候自己debug想想
from collections import defaultdict
def minWindow(s, t):
hash4s = defaultdict(int)
hash4t = defaultdict(int)
left = 0
res = ""
count = 0
for char in t:
hash4t[char] += 1
for right in range(len(s)):
hash4s[s[right]] += 1
if hash4s[s[right]] <= hash4t[s[right]]:
count += 1
while hash4s[s[left]] > hash4t[s[left]]:
hash4s[s[left]] -= 1
left += 1
if count == len(t):
if res == "" or right - left + 1 < len(res):
res = s[left:right + 1]
return res
字符串的排列
https://leetcode.cn/problems/permutation-in-string/
给你两个字符串 s1
和 s2
,写一个函数来判断 s2
是否包含 s1
的排列。如果是,返回 true
;否则,返回 false
。
换句话说,s1
的排列之一是 s2
的 子串 。
示例 1:
输入:s1 = "ab" s2 = "eidbaooo"
输出:true
解释:s2 包含 s1 的排列之一 ("ba").
示例 2:
输入:s1= "ab" s2 = "eidboaoo"
输出:false
提示:
1 <= s1.length, s2.length <= 104
s1
和s2
仅包含小写字母
思路
本题为最小覆盖子串的青春版,主要思想是利用了滑动窗口+哈希表统计出现次数
首先,创建两个数组充当哈希表
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if(s1.size() > s2.size()) return false;
vector<int> hash_s1(26, 0);//创建两个数组用于记录字符串出现的次数
vector<int> hash_s2(26, 0);
int winLen = s1.size();//获取窗口大小
}
};
注意!!!还要将最小的字符串(也就是s1)的长度作为窗口大小保存
然后我们遍历两个字符串的前winLen个元素,即初始时窗口内的元素
class Solution {
public:
bool checkInclusion(string s1, string s2) {
...
for(int i = 0; i < winLen; ++i){
hash_s1[s1[i] - 'a']++;
hash_s2[s2[i] - 'a']++;
}
if(hash_s1 == hash_s2) return true;
}
};
以s1 = "ab" s2 = "eidbaooo"为例,那么此时有
hash_s1 = {0:1, 1:1}
hash_s2 = {5:1, 9:1}
这俩玩意显然不相等,要不然就触发返回条件了
接下来去遍历s2,注意遍历的起始点是winLen而不是0,并且遍历过程中我们需要不断移动窗口
class Solution {
public:
bool checkInclusion(string s1, string s2) {
...
for(int right = winLen; right < s2.size(); ++right){
hash_s2[s2[right - winLen] - 'a']--;
hash_s2[s2[right] - 'a']++;
if(hash_s1 == hash_s2) return true;
}
return hash_s1 == hash_s2;
}
};
移动窗口的过程中,不断判断两个哈希表是否满足条件,满足就返回
遍历结束再次判断,返回判断结果
代码
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if(s1.size() > s2.size()) return false;
vector<int> hash_s1(26, 0);//创建两个数组用于记录字符串出现的次数
vector<int> hash_s2(26, 0);
int winLen = s1.size();//获取窗口大小
for(int i = 0; i < winLen; ++i){//遍历两字符串的前winLen个值,也就是第一个窗口中的值
hash_s1[s1[i] - 'a']++;
hash_s2[s2[i] - 'a']++;
}//如果此时两个哈希表直接相等了,那么说明在第一个窗口就已经确定s2包含s1的排列之一,返回结果即可
if(hash_s1 == hash_s2) return true;
//开始从第二个窗口遍历s2
for(int right = winLen; right < s2.size(); ++right){
hash_s2[s2[right - winLen] - 'a']--;//窗口的左边界向右移动
hash_s2[s2[right] - 'a']++;//窗口的右边界向左移动
//窗口滑动完成,比较此时两哈希表是否相等
if(hash_s1 == hash_s2) return true;
//不相等就继续滑动
}//遍历完s2最后再判断一次两表是否相等,返回结果
return hash_s1 == hash_s2;
}
};
从本题可以直观体会到,双指针与滑动窗口的一个区别
滑动窗口的精髓在于"缩小窗口"这一操作,不同的场景会有不同的缩小时机
本题中,窗口是固定的,因此右边界移动时左边界也必须跟着移动来保证窗口大小固定
找到字符串中所有字母异位词
https://leetcode.cn/problems/find-all-anagrams-in-a-string/description/
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
提示:
1 <= s.length, p.length <= 3 * 104
s 和 p 仅包含小写字母
代码
class Solution {
public:
//滑动窗口
vector<int> findAnagrams(string s, string p) {
if(s.size() < p.size()) return vector<int>();
vector<int> hash_s(26, 0);
vector<int> hash_p(26, 0);
int winLen = p.size();
vector<int> res;
//遍历两个字符串的初始窗口内的元素
for(int i = 0 ; i < winLen; ++i){
hash_s[s[i] - 'a']++;
hash_p[p[i] - 'a']++;
}
//此时如果俩hash相等,那么就获得一个结果,保存其位置(位置就是0处)
if(hash_s == hash_p) res.push_back(0);
//然后从第二个窗口开始遍历
for(int right = winLen; right < s.size(); ++right){
hash_s[s[right - winLen] - 'a']--;//左边界缩窗
hash_s[s[right] - 'a']++;//右边界移动
if(hash_s == hash_p) res.push_back(right - winLen + 1);
}
return res;
}
};
【LeetCode滑动窗口专题】水果成篮 + 最小覆盖子串(hard)+ 字符串的排列的更多相关文章
- LeetCode 滑动窗口题型整理
一.滑动窗口题型模板 /* * 滑动窗口类型: 模板 */ public List<Integer> slideWindowMode(String s, String t) { // 1 ...
- 【Leetcode 滑动窗口】顺次数(1291)
题目 我们定义「顺次数」为:每一位上的数字都比前一位上的数字大 1 的整数. 请你返回由 [low, high] 范围内所有顺次数组成的 有序 列表(从小到大排序). 示例 1: 输出:low = ...
- LeetCode - 滑动窗口最大值
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 输入: nums ...
- [Swift]LeetCode904. 水果成篮 | Fruit Into Baskets
In a row of trees, the i-th tree produces fruit with type tree[i]. You start at any tree of your cho ...
- 7、滑动窗口套路算法框架——Go语言版
前情提示:Go语言学习者.本文参考https://labuladong.gitee.io/algo,代码自己参考抒写,若有不妥之处,感谢指正 关于golang算法文章,为了便于下载和整理,都已开源放在 ...
- Leetcode(三)无重复字符的最长子串
3. 无重复字符的最长子串 题目描述 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最 ...
- [LeetCode] 76. 最小覆盖子串 ☆☆☆☆☆(滑动窗口)
https://leetcode-cn.com/problems/minimum-window-substring/solution/hua-dong-chuang-kou-suan-fa-tong- ...
- [LeetCode]438. 找到字符串中所有字母异位词、76. 最小覆盖子串(滑动窗口解决子串问题系列)
题目438. 找到字符串中所有字母异位词 给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引. 说明: 字母异位词指字母相同,但排列不同的字符 ...
- leetcode全部滑动窗口题目总结C++写法(完结)
3. 无重复字符的最长子串 A: 要找最长的无重复子串,所以用一个map保存出现过的字符,并且维持一个窗口,用le和ri指针标识.ri为当前要遍历的字符,如果ri字符在map中出现过,那么将le字符从 ...
- 滑动窗口通用解leetcode字符串匹配问题
滑动窗口,这玩意解决一些字符串匹配的题目是真的挺好用的,虽然本质还是双指针. 思路: 1.维护一个窗口,不断的向右边移动 2.满足要求后,移动左边,当不满足时,跳出. 3.重复1,2.得出答案. 下面 ...
随机推荐
- 【转帖】淫技巧 | 如何查看已连接的wifi密码
主题使用方法:https://github.com/xitu/juejin-markdown-themes theme: juejin highlight: github 一.引言 在实际工作中,常常 ...
- [转帖]Tail Latency学习
https://www.cnblogs.com/Rohn/p/15123758.html Latency,中文译作延迟,Tail Latency即尾延迟. 实际生产中的Latency是一种(概率)分布 ...
- Redis 的简单学习与整理
Redis 的简单学习与整理 背景 最近一直进行Redis性能调优和高可用的课题 但是不管什么课题,第一步应该是学习与使用redis 之前总结过 rdb 与 rdr 分析 键值对等内容. 但是发现想要 ...
- MySQL新增数据,修改数据,删除数据
连接本地mysql语句 mysql -hlocalhost -uroot -proot DML-介绍 DML英文全称是:用来对数据库中表的数据记录进行 增 删 改 操作. 增加使用 insert 删除 ...
- bootstrap ----- bootstrap table表格参数
表格参数: 名称 标签 类型 默认 描述 - data-toggle String 'table' 不用写 JavaScript 直接启用表格. classes data-classes String ...
- easyui 使用不同的url以获取不同数据源信息
转载 https://www.bbsmax.com/A/kjdw1x06JN/ https://blog.csdn.net/lixinhui199/article/details/50724081 参 ...
- 【云原生】为什么要虚拟化,为什么要容器,为什么要Docker,为什么要K8S?
前言 如标题中的问题所提到的虚拟化,容器,Docker和K8s那样,我们不妨这样问:这些技术到底适用于哪些场景,有没有别的技术可以替代?这些技术的优劣在哪里? 下面我将针对性地从以上几个问题的出发点, ...
- Python自动化办公--Pandas玩转Excel数据分析【二】
相关文章: Python自动化办公--Pandas玩转Excel[一] Python自动化办公--Pandas玩转Excel数据分析[三] python处理Excel实现自动化办公教学(含实战)[一] ...
- Hadoop3 No FileSystem for scheme "hdfs"
Hadoop3 No FileSystem for scheme "hdfs" 异常信息: org.apache.hadoop.fs.UnsupportedFileSystemEx ...
- 计算机网络|思维导图|自顶向下方法|MindMaps资料分享
前言 那么这里博主先安利一下一些干货满满的专栏啦! 手撕数据结构https://blog.csdn.net/yu_cblog/category_11490888.html?spm=1001.2014. ...