系统学习算法: 专题二 滑动窗口

news2024/11/30 15:44:57

题目一:

算法原理:

依然第一反应是暴力枚举,将所有的子数组都枚举出来,找到满足条件的长度最小的子数组,但是需要两层循环,时间复杂度来到O(N^2)

接下来就该思考如何进行优化

如果此时的子数组已经满足条件,那么包括该子数组之后的子数组就没必要枚举了,因为长度一定大于这个子数组,不满足题目要求,所以这里我们可以进行优化

然后该数组也是具有单调性,这时你可能有疑问,这个数组不是无序的吗,怎么会有单调性呢

其实单调性不止有从小到大这种递增的单调性或者从大到小这种递减的单调性,还有正数求和的单调性,以及负数求差的单调性

比如这道题,里面的数都是正整数,所以对子数组求和,那么长度越长,和也就一定越大,这也是单调性

那么有单调性的话,我们要想到什么算法呢?当然有双指针和二分啦

其实双指针下面有许多分类,什么快慢双指针,异向双指针,同向双指针等等,其中同向双指针也叫做滑动窗口,即两个指针移动的方向是同向的,那么就比较像一个长度变化的窗口在向左或者向右滑动

而这道题就要用到滑动窗口,算法的通用步骤如下:

1.left=0,right=0,使得两个指针从同一起点出发

2.进窗口,即right往右移动,把窗口拉长

3.判断条件,看看此时是否要出窗口,即left往右移动,把窗口拉窄

4.更新条件(更新条件的位置不确定,要根据题目要求来确定更新的位置)

其中2到4之间是在循环里面的,直到right越界,即窗口被拉出边界了

用这道题来解释

第一步:我们要设置双指针left和right,同时定义一个变量为sum

第二步:在循环right<数组长度时,这时候sum加上right对应的值,然后right++

第三步:判断此时sum有没有达到题目要求

如果sum小了,说明还不需要出窗口,要继续拉长窗口

如果sum大了,说明此时需要出窗口,更新此时的长度,然后把窗口拉窄,让left--,sum同时减去left对应的值,继续循环判断条件,直到不需要出窗口,

最后当right超出数组下标时,退出循环

也是很简单的思路,大了我就减一点,小了我就加一点,最后找到长度最小的情况

只不过这种算法根据单调性,排除了许多没必要枚举的情况,在时间复杂度上只有O(N),即right遍历完数组,即可,空间复杂度也全是常量O(1),但是不要看等会代码有两层循环就认为时间复杂度是O(N^2),要结合实际操作来计算时间复杂度

代码1:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //设置变量
        int n = nums.length, sum = 0, len = Integer.MAX_VALUE;
        //开始循环
        for (int left = 0, right = 0; right < n; right++) {
            sum += nums[right]; // 进窗⼝(小了就加一点)
            while (sum >= target) // 判断
            {
                len = Math.min(len, right - left + 1); // 更新结果
                sum -= nums[left++]; // 出窗⼝(大了就减一点)
            }
        }
        return len == Integer.MAX_VALUE ? 0 : len;//如果不存在符合条件的就返回0
    }
}

题目二:

算法原理:

子串和子数组其实区别不大,都是连续的,只不过一个在字符串内,一个在数组内

依然是先暴力枚举,将所有子串的结果都枚举出来,用两层循环,第一层循环固定起始点,第二层循环固定终点,当出现重复的时候找到终点,退出第二层循环,然后等第一层循环结束,找到其中子串长度最大的值即可,同样时间复杂度是O(N^2)

那么如何判断是否重复呢,可以采用哈希表

也就是第一种方法:暴力+哈希

那么如何优化呢,我们可以在暴力枚举的过程中发现,如果找到第一个子串后,第二个子串的起点没必要又重新来遍历一次,因为第二个子串是第一个子串的子串

比如abcdc

第一次遍历从a开始,找到终点d,则第一个子串为abcd

第二次遍历从b开始,这时就没必要再遍历c,d了,因为bcd是abcd的子串,所以直接判断起点是否与c重复了,如果重复就继续跳过,直到跳过第一个c,这样就直接来到dc子串

那么使用滑动窗口的条件除了单调性,还有连续性,比如找子串就是连续性的,至于怎么想到用滑动窗口,那么就只能多积累经验了

依然用滑动窗口的通用步骤:

先设置left=0,right=0

进入循环,然后right对应的字符扔进哈希表中,right++(进窗口,将窗口拉长)

这时循环进行判断:如果此时是重复的,那么从哈希表中删除left对应的值,left++(出窗口,将窗口拉窄),直到跳过第一次出现重复字符的位置

然后更新此时的长度

最后返回长度即可

当然这道题我们也不一定真要创建一个哈希表,字符最大ASCII码也就到128,直接用数组下标也可以判断

代码1:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        //将字符串拆成一个一个字符的数组
        char[] str=s.toCharArray();
        //用数组当作哈希表
        int[] hash=new int[128];
        //套用滑动窗口通用模板
        int left=0,right=0,n=s.length();
        int ret=0;
        while(right<n){
            //进窗口,str[right]也就是s第right个字符,将该字符的ASCII码值作为数组下标,给该下标的值加1
            //表示出现1次该字符
            hash[str[right]]++;
            //如果值大于1,说明该字符出现了2次
            while(hash[str[right]]>1){
                //出窗口,直到跳过第一次出现该重复字符的位置(将窗口拉窄)
                hash[str[left++]]--;
            }
            //此时的子串是不重复的,找到最长的子串长度
            ret=Math.max(ret,right-left+1);
            //将窗口拉长
            right++;
        }
        return ret;
    }
}

时间复杂度也是降为O(N),空间复杂度如果不使用真正哈希表,用代码这种模拟哈希表的话,空间复杂度会来到O(N),如果用真正的哈希表,只有O(1),所以哈希表这种数据结构是非常重要的

题目三:

算法原理:

如果真的按照题目要求,将0翻转成1,那么就会很麻烦,将数组不停翻来翻去,那么难度直接上升好几个维度

这时就要转变思维,怎么间接地转换题目要求

因为最多可以翻转k个0,其实也就是说一个子数组中,最多出现k个0

那么这时就不需要进行翻转了,只需要判断子数组中出现多少个0的问题了

而子数组这种连续性的问题,也就可以用滑动窗口算法

仍然也是套用公式(难点主要是间接转变题目的要求,代码都是相同的套路)

先设定两个指针以及一个变量作为长度计数器

然后循环

进窗口

循环判断条件是否出窗口

更新此时长度

代码1:

class Solution {
    public int longestOnes(int[] nums, int k) {
        //初始化
        int left=0,right=0,len=0;
        int count=0;
        //循环
        while(right<nums.length){
            //进窗口
            if(nums[right]==0){
                count++;
            }
            //判断条件
            while(count>k){
                //出窗口
                if(nums[left]==0){
                    count--;
                }
                left++;
            }
            //更新结果
            len=Math.max(len,right-left+1);
            right++;
        }
        //返回结果
        return len;
    }
}

题目四:

算法原理:

根据题目的要求可知,有时候减左边,有时候减右边,完全无从下手

有时候看到题目觉得很难,其实就是题目将简单的方法隐藏起来了,用一种很难的方法来告诉你

这时就要用到正难则反,以后大部分题也都需要用到这个方法

设数组中全部的值的和为sum,左右要减去的总和为题目要求的x,那么中间剩下的连续的数组的和就为sum-x

这一下就回到了我们熟悉的连续性,而不是左减一下右减一下,那么就要想到滑动窗口,因为要求的是最小操作数,所以这时题目就换而言之为求数组中的子数组的和为sum-x的最长子数组

那么接下来就直接套用滑动窗口的模板即可

代码1:

class Solution {
    public int minOperations(int[] nums, int x) {
        //初始化
        int left=0,right=0,sum=0;
        int len=-1;
        //求数组的和
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
        }
        //用来计算此时子数组的和
        int s=0;
        //如果全部之和都没有x大,那么肯定就不可能存在符合题目要求的情况
        if(sum<x){
            return -1;
        }
        //滑动窗口的模板
        while(right<nums.length){
            //进窗口
            s+=nums[right];
            //判断条件
            while(s>sum-x){
                //出窗口
                s-=nums[left];
                left++;
            }
            //更新条件
            if(s==sum-x){
                len=Math.max(right-left+1,len);
            }
            right++;
        }
        return len==-1?-1:nums.length-len;
    }
}

有两点地方需要注意:

1.如果数组之和小于x,那么就说明x减去整个数组都大于0,则肯定不等于0,这时可以直接判断不存在,返回-1

2.len初始化不能为0,因为存在一种情况为整个数组的和刚好等于x,那么此时的len就为0,因为要找到和sum-x的子数组,而sum-x又为0,题目中也说数组的值最小为1,就不存在这样一个子数组,所以没有就为0,

则此时判断是否存在情况的时候,就会出现值为0的两种情况:

没有找到解,len没被修改过,要返回-1;

找到了解,但是len也为0,要返回num.length-len;

刚好是相反的情况,所以len初始化不能为0,即0不能作为判断是否存在的条件,要为-1或者其他负数

题目五:

算法原理:

这种情景题首先要理解题目意思,基本都是看题目大概了解是个什么意思,然后再结合示例明白具体是怎么个要求

读懂题意后,自己转化成简洁语言要求即可

这道题我转化就为:在一个数组中,找到一个最长的子数组,其中这个子数组最多只有两种不同的元素,并返回这个最长子数组的长度

然后把握题目特征(也就是找关键词,在脑海中思考大概用什么算法),子数组问题,连续性

大概就与滑动窗口相关了

仍然先用暴力枚举模拟一下操作过程,然后再进行优化

暴力枚举的话就是起点从下标为0开始往后枚举,直到出现第三种水果,终点停止

那么此时起点往后移动一位,然后继续按照上述操作重复,直到起点为数组的最后一位

那么其中优化的地方就有,如果起点往后移动一位跳过的元素,后面还有该元素,那么这个子数组里面仍然有三种不同的值,所以起点要一次性跳过所有的该元素才行,这是一个优化

然后终点没有必要又从起点开始遍历,因为之前已经遍历过,所以终点只需要保持在原位即可,等到起点跳过某一元素的所有元素,终点再继续往后走

那么如何判断子数组里面有多少种不同的值,只需要把数组下标扔进哈希表即可,用一个变量作为种类计数器进行判断即可

然后就是套用滑动窗口的模板

代码1(哈希表):

class Solution {
    public int totalFruit(int[] f) {
        Map<Integer, Integer> hash = new HashMap<Integer, Integer>(); // 统计窗口的水果种类
        int ret = 0;
        for (int left = 0, right = 0; right < f.length; right++) {
            int in = f[right];
            hash.put(in, hash.getOrDefault(in, 0) + 1); // 进窗⼝
            while (hash.size() > 2) {
                int out = f[left];
                hash.put(out, hash.get(out) - 1); // 出窗⼝
                if (hash.get(out) == 0)
                    hash.remove(out);
                left++;
            }
            // 更新结果
            ret = Math.max(ret, right - left + 1);
        }
        return ret;
    }
}

虽然哈希表的操作时间复杂度都是O(1)级别,但是因为使用到了容器,且操作很频繁的话,时间消耗其实还是挺多的,这时候我们就可以用数组模拟哈希表,因为底下说明了数组中最大的值一定小于数组的长度,所以直接用数组的长度作为模拟数组的长度即可

代码2(用数组模拟哈希表):

class Solution {
    public int totalFruit(int[] fruits) {
        //初始化
        int left=0,right=0,count=0;
        int len=-1;
        //模拟数组
        int[] hash=new int[fruits.length];
        //滑动窗口模板
        while(right<fruits.length){
            //判断是否为新种类
            if(hash[fruits[right]]==0){
                count++;
            }
            //进窗口
            hash[fruits[right]]++;
            //判断条件是否出窗口
            while(count>2){
                //出窗口
                hash[fruits[left]]--;
                if(hash[fruits[left]]==0){
                    count--;
                }
                left++;
            }
            //更新条件
            len=Math.max(len,right-left+1);
            right++;
        }
        return len;
    }
}

时间消耗上比用哈希表大大优化了,基本上是质的飞跃

题目六:

算法原理:

这道题大致分为两步,第一步是怎么判断异位词,第二步是怎么判断字符串中所有的异位词

首先解决第一步,最暴力的方式就是将两个字符串先按照字典序排序,然后再进行比较,这样肯定可以比较出来是否是异位词,但是效率不高

再多想一想的话,就可以想到通过比较两个字符串中,每次字符出现的次数是否相等,那么这样就不需要进行排序再比较了,直接通过字符数是否相等即可判断两个字符串是否是异位词,那么就可以采用哈希表,将字符与出现个数建立一一映射关系,采用两个哈希表,一个统计s,一个统计p

第二步的话,可以想到滑动窗口,滑动窗口大致分为两类:窗口大小不确定,和窗口大小固定,而这道题就是滑动窗口大小固定的题,因为窗口大小一定是等于p字符串的长度

那么接下来通过遍历,将s字符串用滑动窗口的步骤,判断是否是异位词即可,但是步骤中需要稍微修改,那就是之前窗口大小不确定的题中判断条件是不确定left要移动多少,所以用到是循环,但是窗口固定大小就可以确定right++,那么left也只用++一次即可,所以用if就好

还有一个优化,那就是每次判断异位词的,都是要将每种字符一个一个比较,效率不是很高,可以采用count变量作为统计当前窗口的有效字符,而如何判断进窗口后和出窗口后的字符是不是有效字符呢,只需要判断该字符在s哈希表出现的次数小于等于p哈希表的次数,说明该字符是有效的,count++,如果大于,那就说明这个字符是无效字符,出不出都无所谓,count不需要改变

最后判断count是否等于p的长度,如果等于,就说明全都是有效字符,那么肯定是异位词,将left的值加到顺序表中,反之则不是异位词

代码1(哈希表):

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        //map用来统计p字符串中每个字符的数量,map1用来统计s遍历到的子串的字符数量
        HashMap<Character,Integer> map=new HashMap<>();
        HashMap<Character,Integer> map1=new HashMap<>();
        ArrayList<Integer> list=new ArrayList<>();
        //将p里面字符和出现数量建立一一映射的关系
        for(int i=0;i<p.length();i++){
            char ch=p.charAt(i);
            if(map.get(ch)==null){
                map.put(ch,1);
            }else{
                int val=map.get(ch);
                map.put(ch,val+1);
            }
        }
        //开始滑动窗口,count作为判断条件
        int count=0,left=0,right=0;
        while(right<s.length()){
            //进窗口,将元素放进map1
            char in=s.charAt(right);
            if(map1.get(in)==null){
                map1.put(in,1);
            }else{
                int val=map1.get(in);
                map1.put(in,val+1);
            }
            //滑动右边界
            right++;
            //如果此时的字符属于有效字符
            if(map1.get(in)<=map.getOrDefault(in,0)){
                count++;
            }
            //如果此时窗口的长度大于p字符串
            if(right-left>p.length()){
                //出窗口,将元素拿出来
                char out=s.charAt(left);
                //如果此时的字符属于有效字符
                if(map1.get(out)<=map.getOrDefault(out,0)){
                    count--;
                }
                map1.put(out,map1.get(out)-1);
                //滑动左窗口
                left++;
            }
            //如果此时是异位词
            if(count==p.length()){
                list.add(left);
            }
        }
        return list;
    }
}

当然也可以用数组模拟哈希表

代码2(用数组模拟哈希表):

class Solution
{
     public List<Integer> findAnagrams(String ss, String pp) 
     {
         List<Integer> ret = new ArrayList<Integer>();
         //如果不习惯charAt,也可以先转化为字符数组,用下标来使用字符
         char[] s = ss.toCharArray();
         char[] p = pp.toCharArray();
         int[] hash1 = new int[26]; // 统计字符串 p 中每⼀个字符出现的个数
         for(char ch : p){
            hash1[ch - 'a']++;
         }
         int[] hash2 = new int[26]; // 统计窗⼝中每⼀个字符出现的个数
         int m = p.length;
         for(int left = 0, right = 0, count = 0; right < s.length; right++)
         {
             char in = s[right];
             // 进窗⼝ + 维护 count
             if(++hash2[in - 'a'] <= hash1[in - 'a']) count++; 
             if(right - left + 1 > m) // 判断
             {
                 char out = s[left++];
                 // 出窗⼝ + 维护 count
                 if(hash2[out - 'a']-- <= hash1[out - 'a']){
                    count--; 
                 }
             }
             // 更新结果
             if(count == m){
                ret.add(left);
             }
         }
             return ret;
     }
}

题目七:

算法原理:

和上面一道题很类似,上面那题判断异位词是字符,而这道是字符串,所以可以借鉴上面题目的解题步骤,但是也有几点不同,那就是滑动窗口的分割起点要多次循环,也就是要进行多次滑动窗口,因为对s如果从0开始,往后按照words字符串的长度len切割,有可能切不到,所以要从0开始切割,从1开始切割,……直到len-1开始切割

而且滑动窗口每次移动也不是一步一步移了,而是移动字符串的长度len,left和right也是同理

还有一个细节,那就是每次滑动窗口结束后,准备重新开始新的滑动窗口,要进行哈希表清零和count清零操作

具体就是代码实现,这道题也是算比较难的考验算法原理转化为代码形式的题

代码1:

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        //map存words里面的映射关系,map1存滑动窗口中的映射关系
        HashMap<String,Integer> map=new HashMap<>();
        HashMap<String,Integer> map1=new HashMap<>();
        List<Integer> list=new ArrayList<>();
        //将words存进哈希表
        for(String str:words){
            if(map.get(str)==null){
                map.put(str,1);
            }else{
                int val=map.get(str);
                map.put(str,val+1);
            }
        }
        //len为words中一个字符串的长度,l为异位词的长度
        int left=0,right=0,count=0,len=words[0].length(),l=0;
        for(int i=0;i<words.length;i++){
            l+=len;
        }
        //最外层循环是滑动窗口的次数
        for(int cishu=0;cishu<len;cishu++){
            //确定left和right的起点
            right=cishu;
            left=cishu;
            //开始本次的滑动窗口
            while(right<s.length()&&left<=s.length()-l){
                //进窗口
                //String因为不可变性,+=拼接效率太低,可以采用StringBuffer进行拼接
                StringBuffer sb=new StringBuffer("");
                if(right+len<=s.length()){
                    for(int i=right;i<right+len;i++){
                        sb.append(s.charAt(i));
                    }
                    //因为哈希表泛型定义的String,所以要转回来
                    String s1=sb.toString();
                    map1.put(s1,map1.getOrDefault(s1,0)+1);
                    //判断加进来的是否是有效字符串
                    if(map1.get(s1)<=map.getOrDefault(s1,0)){
                        count++;
                    }
                    //右窗口滑动
                    right+=len;
                    //判断滑动窗口有没有比异位词还长
                    if(right-left>l){
                        //出窗口
                        //将之前字符串删除
                        sb.delete(0,len);
                        for(int i=left;i<left+len;i++){
                            sb.append(s.charAt(i));
                        }
                        s1=sb.toString();
                        //如果删之前发现该字符串是有效字符串
                        if(map1.get(s1)<=map.getOrDefault(s1,0)){
                            count--;
                        }
                        //删除
                        map1.put(s1,map1.get(s1)-1);
                        //左窗口滑动
                        left+=len;
                    }
                    //如果此时滑动窗口中是异位词
                    if(count==words.length){
                        list.add(left);
                    }            
                }else{//如果right后面的字符构不成一个len长度的字符串
                    break;
                }
            }
            //进行清零,为下一次滑动窗口做准备
            count=0;
            map1.clear();
        }
        return list;
    }
}

里面用到了许多方法,以及优化上String的拼接改为StringBuffer(当然这里也可以使用substring方法),一次性写出来会比较困难,本人也是经过多次调试修改才写出来,确实很锻炼代码能力

题目八:

算法原理:

题目的意思也很简单,就是找到s字符串中涵盖t字符串所有字符的最小子串,还是先用暴力枚举的方法,大致理清操作步骤,定义left和right,left和right都从0开始,如果出现了t中的字符,对应计数器就++,然后right一直往右移动,直到最后一个字符,然后left往右移动一步,right又从left位置开始,继续往右移动,循环上面的步骤,直到left也到最后的字符位置

这是暴力枚举所有子串的情况的方法,里面依旧有许多优化的空间,比如right不需要又重新回到left的位置,只需要固定不动,等left自己移动即可,还有在判断是否符合涵盖子串的时候,按理来说是比较两个哈希表,但是根据上题提到的方法,可以用count来记录每个字符的种类个数,如果大于等于种类个数,就说明该子串是涵盖子串,这时候只需要比较是否是最小的子串,看看是否需要更改结果即可

大致与前几题类似,就不多赘述了

当然,一开始我们可以判断t的字符串长度是否大于s,因为如果大于了,那么s里面肯定就不可能涵盖t的所有字符的子串

代码1(哈希表):

class Solution {
    public String minWindow(String s, String t) {
        //示例3的情况,直接返回空字符串
        if(t.length()>s.length()){
            return "";
        }
        //map1用来统计t的字符种类,map2用来统计s的字符种类及出现个数
        HashMap<Character,Integer> map1=new HashMap<>();
        HashMap<Character,Integer> map2=new HashMap<>();
        //将t建立起一一映射的关系
        for(int i=0;i<t.length();i++){
            if(map1.get(t.charAt(i))==null){
                map1.put(t.charAt(i),1);
            }else{
                int val=map1.get(t.charAt(i));
                map1.put(t.charAt(i),val+1);
            }
        }
        //count是有效字符种类,len是当前子串长度,cur是最小子串的起始位置,min是最小子串的长度
        int left=0,right=0,count=0,len=0,cur=0,min=0;
        //开始滑动窗口的步骤
        while(right<s.length()){
            //进窗口
            map2.put(s.charAt(right),map2.getOrDefault(s.charAt(right),0)+1);
            //如果进的是有效字符,字符种类加1
            if(map1.getOrDefault(s.charAt(right),0)>=map2.get(s.charAt(right))){
                count++;
            }
            //长度加1
            len++;
            //窗口右边界扩大
            right++;
            //判断条件(count的有效字符种类大于t的长度,即当前窗口内的字符串已经涵盖了t的所有字符)
            while(count>=t.length()){
                //更新条件,看看当前子串是否是最小子串(其中用min==0作为一开始的最小子串)
                if(len<min||min==0){
                    //将最小子串的起始位置和长度进行更新
                    cur=left;
                    min=len;
                }
                //出窗口(先判断当前要出的是否是有效字符,且是否将该有效字符的所有个数全出完)
                if(map2.get(s.charAt(left))<=map1.getOrDefault(s.charAt(left),0)){
                    count--;
                }
                //出窗口
                map2.put(s.charAt(left),map2.get(s.charAt(left))-1);
                //窗口左边界缩小
                left++;
                //长度减1
                len--;
            }
        }
        //返回最小字符的起始位置后的min长度的字符串
        return s.substring(cur,cur+min);
    }
}

 我们之前提到过虽然哈希表这个容器的时间复杂度为O(1),但是内存消耗还是很大的,所以如果能用数组模拟哈希表的话,就用数组模拟,这道题的题目提示中也有写s,t字符串都是由英文字符构成,所以直接创建长度为128的数组即可

代码2(用数组模拟哈希表):

class Solution {
    public String minWindow(String ss, String tt) {
        //如果charAt用着不习惯,可以先转成数组,用下标来使用
        char[] s = ss.toCharArray();
        char[] t = tt.toCharArray();
        int[] hash1 = new int[128]; // 统计字符串 t 中每⼀个字符的频次
        int kinds = 0; // 统计有效字符有多少种
        for (char ch : t)
            if (hash1[ch]++ == 0)
                kinds++;
        int[] hash2 = new int[128]; // 统计窗⼝内每个字符的频次
        int minlen = Integer.MAX_VALUE, begin = -1;
        for (int left = 0, right = 0, count = 0; right < s.length; right++) {
            char in = s[right];
            if (++hash2[in] == hash1[in])
                count++; // 进窗⼝ + 维护 count
            while (count == kinds) // 判断条件
            {
                if (right - left + 1 < minlen) // 更新结果
                {
                    minlen = right - left + 1;
                    begin = left;
                }
                char out = s[left++];
                if (hash2[out]-- == hash1[out])
                    count--; // 出窗⼝ + 维护 count
            }
        }
        if (begin == -1)
            return new String();
        else
            return ss.substring(begin, begin + minlen);
    }
}

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

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

相关文章

QGIS制作xyz切片(mbtiles)

MBTiles是由MapBox制定的一种将瓦片地图数据存储到SQLite数据库中并可快速使用&#xff0c;管理和分享的规范。它使得数以百万的瓦片数据存储在一个文件中&#xff0c;而且SQLite数据库支持多种平台&#xff0c;所以使用MBTiles在移动设备上浏览瓦片数据是比较理想的方式。 QGI…

软件测试——性能测试工具JMeter

1.JMeter介绍 Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件。JMeter小巧轻便且免费&#xff0c;逐渐成为了主流的性能测试工具&#xff0c;是每个测试人员都必须要掌握的工具之一。 环境要求&#xff1a; ​ 需要Java8或者更高的版本。 1.1 JMeter的下…

【C++算法】20.二分查找算法_x 的平方根

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;图解 题目链接&#xff1a; 69. x 的平方根 题目描述&#xff1a; 解法 暴力解法&#xff1a; 如果x17 从1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5......这些数里面找他们的平方…

拥抱 OpenTelemetry:阿里云 Java Agent 演进实践

作者&#xff1a;陈承 背景 在 2018 年的 2 月&#xff0c;ARMS Java Agent 的第一个版本正式发布&#xff0c;为用户提供无侵入的的可观测数据采集服务。6 年后的今天&#xff0c;随着软件技术的迅猛发展、业务场景的逐渐丰富、用户规模的快速增长&#xff0c;我们逐渐发现过…

【项目日记】仿mudou的高并发服务器 --- 实现HTTP服务器

对于生命&#xff0c;你不妨大胆一点&#xff0c; 因为我们始终要失去它。 --- 尼采 --- ✨✨✨项目地址在这里 ✨✨✨ ✨✨✨https://gitee.com/penggli_2_0/TcpServer✨✨✨ 仿mudou的高并发服务器 1 前言2 Util工具类3 HTTP协议3.1 HTTP请求3.2 HTTP应答 4 上下文解析模块…

从0在自己机器上部署AlphaFold 3

本文介绍如何在自己本地机器上安装AlphaFold 3。 在10月份&#xff0c;Google DeepMind的首席执行官Demis Hassabis和高级研究科学家John M. Jumper所领导的团队&#xff0c;利用AI技术成功预测了几乎所有已知蛋白质的结构&#xff0c;开发出备受赞誉的AlphaFold&#xff0c;并…

faiss库中ivf-sq(ScalarQuantizer,标量量化)代码解读-6

调试 经过gdb调试获取的调用栈内容如下&#xff0c;链接&#xff1a; 步骤函数名称文件位置说明1faiss::IndexFlatCodes::add/faiss/IndexFlatCodes.cpp:24在 add 方法中&#xff0c;检查是否已经训练完成&#xff0c;准备添加向量到索引中。2std::vector<unsigned char&g…

SQL进阶——子查询与视图

在SQL中&#xff0c;子查询和视图是两种强大的技术&#xff0c;用于处理复杂的查询、提高代码的重用性以及优化查询性能。子查询允许开发者在查询中嵌套其他查询&#xff0c;而视图则是对复杂查询的封装&#xff0c;可以简化开发工作并提高代码的可维护性。 本章将深入探讨如何…

【论文阅读】 Learning to Upsample by Learning to Sample

论文结构目录 一、之前的上采样器二、DySample概述三、不同上采样器比较四、整体架构五、设计过程&#xff08;1&#xff09;初步设计&#xff08;2&#xff09;第一次修改&#xff08;3&#xff09;第二次修改&#xff08;4&#xff09;第三次修改 六、DySample四种变体七、复…

Online Judge——【前端项目初始化】项目通用布局开发及初始化

目录 一、新建layouts二、更新App.vue文件三、选择一个布局&#xff08;Layout&#xff09;四、通用菜单Menu的实现菜单路由改为读取路由文件 五、绑定跳转事件六、同步路由到菜单项 一、新建layouts 这里新建一个专门存放布局的布局文件layouts&#xff1a; 然后在该文件夹&…

uniapp首页样式,实现菜单导航结构

实现菜单导航结构 1.导入字体图标库需要的文件 2.修改引用路径iconfont.css 3.导入到App.vue中 <style>import url(./static/font/iconfont.css); </style>导航区域代码 VUE代码 <template><view class"home"><!-- 导航区域 --><…

《代码随想录》刷题笔记——栈与队列篇【java实现】

文章目录 用栈实现队列用队列实现栈有效的括号我的解法代码随想录 删除字符串中的所有相邻重复项我的解法代码随想录栈解法字符串充当栈※双指针 逆波兰表达式求值我的解法代码随想录 滑动窗口最大值我的解法暴力解法暴力解法一点优化单调队列 代码随想录单调队列 前 K 个高频元…

STM32 ADC --- 知识点总结

STM32 ADC — 知识点总结 文章目录 STM32 ADC --- 知识点总结cubeMX中配置注解单次转换模式、连续转换模式、扫描模式单通道采样的情况单次转换模式&#xff1a;连续转换模式&#xff1a; 多通道采样的情况禁止扫描模式&#xff08;单次转换模式或连续转换模式&#xff09;单次…

UaGateway:实现OPC DA和OPC UA的高效转换

随着工业4.0和智能制造的深入推进&#xff0c;工业自动化系统之间的互联互通需求日益迫切。UaGateway作为一种高效的协议转换工具&#xff0c;正在成为各类工业应用中不可或缺的桥梁。本文将重点介绍UaGateway在实现OPC DA到OPC UA转换方面的主要功能、应用场景和实际案例。 Ua…

安能物流 All in TiDB 背后的故事与成果

导读 在数字化转型的浪潮中&#xff0c;安能物流通过技术创新不断提升物流效率&#xff0c;迈出了全链路 All in TiDB 的重要一步。本文将深入探讨安能物流如何选择 TiDB 作为核心数据库&#xff0c;以应对高并发、数据处理能力和系统可扩展性等挑战。通过 TiDB 的弹性扩展能力…

回声消除延时估计的一些方法

在音频信号处理&#xff0c;尤其是在回声消除和语音通信中&#xff0c;延时估计是一个至关重要的任务。回声消除技术旨在减少或消除在语音通信中由于信号反射而产生的回声。为了有效地实现这一点&#xff0c;系统需要准确估计发送信号和接收信号之间的延迟。通过了解延迟&#…

从简单的自动化脚本到复杂的智能助手:Agent技术的实践与应用

现代软件开发中&#xff0c;Agent技术正在悄然改变着我们构建应用程序的方式。一个Agent就像是一个能独立完成特定任务的智能助手&#xff0c;它可以感知环境、作出决策并采取行动。让我们通过实际案例&#xff0c;深入了解如何运用Agent技术来构建智能系统。 想象你正在开发一…

postman使用正则表达式提取数据实战篇!

之前篇章中postman多接口关联使用的是通过JSON提取器的方式进行提取。 除了JSON提取器提取数据外还可通过另一种方式——正则表达式来提取数据。 1、使用正则表达式提取器实现接口关联&#xff0c;match匹配 正则匹配表达式将需要提取的字段key:value都放入表达式中&#xff…

Flume 与 Kafka 整合实战

目录 一、Kafka 作为 Source【数据进入到kafka中&#xff0c;抽取出来】 &#xff08;一&#xff09;环境准备与配置文件创建 &#xff08;二&#xff09;创建主题 &#xff08;三&#xff09;测试步骤 二、Kafka 作为 Sink数据从别的地方抽取到kafka里面】 &#xff08;…

存储服务器一般做是做什么阵列?详细列举一下

存储服务器通常使用 RAID&#xff08;Redundant Array of Independent Disks&#xff09; 阵列技术来管理磁盘&#xff0c;以提高数据的性能、可靠性和可用性。所选择的 RAID 类型取决于存储服务器的具体用途和需求&#xff0c;比如性能要求、容量需求、容错能力等。 以下是存…