二刷刷到滑动窗口,发现有一些细节和遗漏,在此补充

实际上关于滑动窗口的题还有一题:最小长度的子数组

进入正题

水果成篮

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),hsht

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/

给你两个字符串 s1s2 ,写一个函数来判断 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
  • s1s2 仅包含小写字母

思路

本题为最小覆盖子串的青春版,主要思想是利用了滑动窗口+哈希表统计出现次数

首先,创建两个数组充当哈希表

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)+ 字符串的排列的更多相关文章

  1. LeetCode 滑动窗口题型整理

    一.滑动窗口题型模板 /* * 滑动窗口类型: 模板 */ public List<Integer> slideWindowMode(String s, String t) { // 1 ...

  2. 【Leetcode 滑动窗口】顺次数(1291)

    题目 我们定义「顺次数」为:每一位上的数字都比前一位上的数字大 1 的整数. 请你返回由 [low, high] 范围内所有顺次数组成的 有序 列表(从小到大排序).   示例 1: 输出:low = ...

  3. LeetCode - 滑动窗口最大值

    给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 输入: nums ...

  4. [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 ...

  5. 7、滑动窗口套路算法框架——Go语言版

    前情提示:Go语言学习者.本文参考https://labuladong.gitee.io/algo,代码自己参考抒写,若有不妥之处,感谢指正 关于golang算法文章,为了便于下载和整理,都已开源放在 ...

  6. Leetcode(三)无重复字符的最长子串

    3. 无重复字符的最长子串 题目描述 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最 ...

  7. [LeetCode] 76. 最小覆盖子串 ☆☆☆☆☆(滑动窗口)

    https://leetcode-cn.com/problems/minimum-window-substring/solution/hua-dong-chuang-kou-suan-fa-tong- ...

  8. [LeetCode]438. 找到字符串中所有字母异位词、76. 最小覆盖子串(滑动窗口解决子串问题系列)

    题目438. 找到字符串中所有字母异位词 给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引. 说明: 字母异位词指字母相同,但排列不同的字符 ...

  9. leetcode全部滑动窗口题目总结C++写法(完结)

    3. 无重复字符的最长子串 A: 要找最长的无重复子串,所以用一个map保存出现过的字符,并且维持一个窗口,用le和ri指针标识.ri为当前要遍历的字符,如果ri字符在map中出现过,那么将le字符从 ...

  10. 滑动窗口通用解leetcode字符串匹配问题

    滑动窗口,这玩意解决一些字符串匹配的题目是真的挺好用的,虽然本质还是双指针. 思路: 1.维护一个窗口,不断的向右边移动 2.满足要求后,移动左边,当不满足时,跳出. 3.重复1,2.得出答案. 下面 ...

随机推荐

  1. jcmd的简单总结

    jcmd的简单总结 背景 自从2019年公司转向java技术路线. 一直断断续续的在学习java相关的技术内容. 但是总感觉学的不是很深入. 这周比较累.也不想在学新东西了. 所以想着再总结一下jcm ...

  2. reposync与createrepo创建离线yum源的方法

    背景 昨天晚上进行了在线升级银河麒麟V10SP2的audit和mate-indicator的rpm包 今天想了下,如果机器无法上网. 必须得在公司内部搭建一套离线的rpm源进行处理 想了下还是使用re ...

  3. 大数据平台Bug Bash大扫除最佳实践

    一.背景 随着越来越多的"新人"在日常工作以及大促备战中担当大任,我们发现仅了解自身系统业务已不能满足日常系统开发运维需求.为此,大数据平台部门组织了一次Bug Bash活动,既能 ...

  4. echarts饼状图自定义legend的样式付费

    先看效果图 代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...

  5. 学到了,原来 gzip 是种`连续分块`的压缩算法

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 我想要表述的是:假设有 10 mb的数据使用 gzip 算 ...

  6. HEVC扩展备用安装方法

    这个玩意微软商店免费但是下架了,购买需要RMB 安装 转到 https://store.rg-adguard.net/ 在左侧的下拉菜单选择"ProductId" 把链接中&quo ...

  7. 手撕Vuex-添加全局$store

    经过上一篇的介绍,了解到了 Vuex 的实现本质就是一个插件,所以要做的事情就是实现这个插件的代码编写即可. 本篇文章主要是实现一个全局的 $store,这个 $store 是挂载在 Vue 的原型上 ...

  8. TienChin 渠道管理-添加渠道

    在我们平时新建一个全新的 Java 类,这个类需要存放的包不存在,可以使用如下的方式进行创建: 含义就是说,将 ChannelVO 这个类放在 vo 这个包当中,如果存在则不创建,存在就将新建的类放入 ...

  9. 虚拟IP绑定公网IP访问

    绑定公网 IP 我们目前的虚拟 IP,还不能通过公网的形式进行访问,我们首先,来使用内部的 IP 进行访问看看效果如下: curl 虚拟IP 如上图我访问了两次,第一次访问返回的是 2222 的 ng ...

  10. PaddleHub--飞桨预训练模型应用工具{风格迁移模型、词法分析情感分析、Fine-tune API微调}【一】

    相关文章: 基础知识介绍: [一]ERNIE:飞桨开源开发套件,入门学习,看看行业顶尖持续学习语义理解框架,如何取得世界多个实战的SOTA效果?_汀.的博客-CSDN博客_ernie模型 百度飞桨:E ...