滑动窗口算法专题

滑动窗口简介

滑动窗口就是利用单调性,配合同向双指针来优化暴力枚举的一种算法。

该算法主要有四个步骤

  1. 先进进窗口

  2. 判断条件,后续根据条件来判断是出窗口还是进窗口

  3. 出窗口

4.更新结果,更新结果这个步骤是不确定的,应题目要求判断是在进窗口前更新结果还是出窗口前更新结果。

1. 长度最小的子数组

题目链接:209. 长度最小的子数组 - 力扣(LeetCode)

题目细节信息:

1.数组中都是正数 2.在数组中找到长度最小的子数组且子数组中的元素和小于target值

解法:滑动窗口

我们先定义一个left指针和right指针,left和right之间就是一个窗口。在定义一个变量sum来记录[left,right]区间的和。

根据题目要求,我们先确定第一个sum大于等于target值得右边界,所以我们先让right不断进窗口。

以题目中的实例1为例

接着我们根据sum的值来判断是否进窗口还是出窗口。sum的值无非会遇到两种情况。

当sum小于等于target的时候,我们先要更新最小长度和sum的值,接着在进窗口,即让left++

如下图:

之前left指向的元素已经不在窗口里面了,这也是理解出窗口的一个图解。

当sum小于target时,我们进窗口进行了,即right++

滑动窗口的正确性

为什么能判断滑动窗口是对的呢?

因为数组中的数据都是正数,当right找到第一个边界使sum大于等于target的值时,我们就没必要让right继续向后走了,因为数组中都是正数,right继续走下去,sum会变大,但是len也会变长,此时len肯定就不是我们要的结果了。所以不让right向后走,就避免了其他不符合题意情况的枚举了。

代码实现

代码一:我写的形式

java 复制代码
    public int minSubArrayLen(int target, int[] nums) {
        int n=nums.length;
        int left=0,right=0;
        int ret=Integer.MAX_VALUE;
        int sum=nums[right];
        while(right<n){
            if(sum<target){
                right++;//进窗口
                if(right<n){
                    sum+=nums[right];
                }
            }else{
                ret=Math.min(ret,right-left+1);//更新长度最小值
                sum-=nums[left];//更新sum值
                left++;//出窗口
            }
        }
        return ret==Integer.MAX_VALUE?0:ret;
    }

代码二:

java 复制代码
    public int minSubArrayLen(int target, int[] nums) {
        int n=nums.length;
        int len=Integer.MAX_VALUE;
        int sum=0;
        for(int left=0,right=0;right<n;right++){//进窗口
            sum+=nums[right];
            while(sum>=target){//这里要用while循环
                len=Math.min(len,right-left+1);//更新最小长度
                sum-=nums[left];//更新sum的值
                left++;//出窗口
            }
        }
        return len==Integer.MAX_VALUE?0:len;
    }

2.无重复字符的最长字串

题目链接:3. 无重复字符的最长子串 - 力扣(LeetCode)

题目解析:在字符串中找到一个连续且无重复字符的子字符串,并返回其长度。

解法一:暴力枚举(会超时)

枚举从字符串的第一个字符开始往后,无重复字符的子串可以到什么位置,找出一个最大长度的即可。

因此,我们可以通过一个哈希表来记录往后枚举的过程中,字符是否出现重复的情况。

java 复制代码
//时间复杂度O(n^2)
//空间复杂度O(1)
import java.util.*;
class Solution {
    public int lengthOfLongestSubstring(String s) {
        int len = s.length();
        int ret = 0;
        for(int i = 0; i < len; i++) {
            int[] hash = new int[128];
            for(int j = i; j < len; j++) {
                hash[s.charAt(j)]++;
                if(hash[s.charAt(j)] > 1) {
                    break;
                }
                ret = Math.max(ret, j - i + 1);

            }
        }
        return ret;
    }
}

解法二:滑动窗口

此时,我们可以通过滑动窗口来优化上面的暴力枚举。

首先,先通过一种枚举的情况来分析,如下图

当我们枚举时,当right遇到第一个重复的字符a时,我们就不必要让right继续往后走了,因为前面的left的位置没变,当right继续往后走,left和right之间是一定有重复的字符的。

所以,此时,我们可以让right先固定在原地,先让left指针往后走,直到left指针跳过重复的字符,right才能继续完后走。

但是,当left往后走的时候,right没必要往回退到和left一样的位置,因为当left没有跳过第一个重复的字符时,right撑死只能走到第二个a的位置,且left往后走了,此时子串的长度肯定是比left没有往后走时短的。

两个指针没有回退,这时就可以使用滑动窗口了。

这里先解释下上面的hash数组的意思

这里hash数组的下标为字符串中字符的ASCII值,hash数组中的数据是该字符的出现次数。

滑动川口的解题步骤:

1.进窗口:让字符进入hash表中

2.判断和出窗口:判断该字符是否重复出现,如果重复出现,则出窗口,即将该字符从hash表中删除。

3.更新结果:这里是先进行判断后,才执行更新的操作。

代码实现:

java 复制代码
时间复杂度:O(n)
空间复杂度:O(n)
    public int lengthOfLongestSubstring(String ss) {
        int n=ss.length();
        char[] s=ss.toCharArray();
        int[] hash=new int[128];
        int left=0,right=0,ret=0;
        while(right<n){
            hash[s[right]]++;//进窗口
            while(hash[s[right]]>1){//判断字符是否重复出现
                hash[s[left++]]--;//出窗口
            }
            ret=Math.max(ret,right-left+1);//更新结果
            right++;
        }
        return ret;        
    }

3. 最大连续1的个数

题目链接:1004. 最大连续1的个数 III - 力扣(LeetCode)

题目解析:最多可以将数组中的k个0翻转为1,返回数组经过翻转后,数组中连续1的最大个数。

虽然题目中是要求我们翻转0,但是如果我们遇到0就将其翻转为1的话,接着进行新的枚举的时候,就又要将翻转过的0,重新翻转为0,此时,代码就会很难写,且很复杂。

其实,我们可以转换为求区间的长度,只要该区间的0的个数没有大于k个就行了。

解法一:暴力枚举+zero计数器

定义一个left和right指针,我们可以让left为起点向后枚举,定义一个zero变量来保存枚举过程中遇到0的个数 ,如果zero的值大于k,此时我们就可以让right指针停在该位置了,因为此时right如果继续走下去,left和right区间就是不符合题目要求了。

也就是说,此时以left为起点的枚举,得到的连续1的长度就是一个最优解了,此时就可以更新结果

所以,我们要换一个起点进行枚举,既让left++,接着让right回到left的位置,以新的left为起点继续,right继续向后枚举,重复上面的步骤。

解法二:滑动窗口

再暴力枚举上进一步优化,当我们让left++的时候,没必要将right重新指向left的位置,因为当zero的值大于k时,right撑死也时只能走到刚才停止的位置,只有我们left跳过一个0的时候,让zero减一,让zero的值小于k时,此时right才可以继续完后枚举。

此时,发现,left和right指针是同向运行,且不会退,我们就可以使用滑动窗口算法来解决该问题。

步骤一:进窗口

当right完后枚举时,遇到1就忽略,如果遇到0,就让zero的值加1

步骤二:判断+出窗口

当zero的值大于k时,我们就出窗口,也就时让left++,如果left遇到1就忽略,如果遇到0,就

让zero的值减1

步骤三:更新结果

此时,更新结果的步骤是在判断的步骤之后。

代码实现:

java 复制代码
//时间复杂度:O(n)
//空间复杂度:O(1) 
   public int longestOnes(int[] nums, int k) {
        int left=0,right=0,zero=0;
        int n=nums.length;
        int ret=0;
        while(right<n){
            if(nums[right]==1){
                right++;
            }else{
                right++;
                zero++;//出窗口
            }
            while(zero>k){//判断
                if(nums[left]==0){
                    zero--;//进窗口
                }
                left++;
            }
            ret=Math.max(ret,right-left);//更新结果
        }
        return ret;
    }

注意:这里更新结果为什么不是right-left+1呢?因为我是再right++之后再更新长度,而不是再right++之前更新长度。

更简练版本:

java 复制代码
    public int longestOnes(int[] nums, int k) {
         int ret = 0;
         for(int left = 0, right = 0, zero = 0; right < nums.length; right++){
                 if(nums[right] == 0) zero++; // 进窗⼝
                 while(zero > k) // 判断
                 if(nums[left++] == 0) zero--; // 出窗⼝
                 ret = Math.max(ret, right - left + 1); // 更新结果
          }
               return ret;
 }

这个版本就是再right++之前更新长度,所以更新长度时是right-left+1

4.将x减到0的最小操作数

题目链接:1658. 将 x 减到 0 的最小操作数 - 力扣(LeetCode)

题目解析:

1.我们每次进行一次删减操作时,我们都要将数组最左边或最右边的元素删去,供下一次删减操作时使用

2.数组里面的都是正数

在该题中,只有数组里面全是正数,我们才能使用滑动窗口解决

分析:因为当数组里面有负数或者为0的数据时,当right到达第一个停止的位置时,当我们的tmp减去一个负数或者数据为0的数时,由于负数或0的缘故,会导致[left,right]区间的和有可能是等于或大于tmp的,所以,此时进行新的枚举时,right有可能会向前退,也有可能继续向后退。

解题思路转换:解决该题的时候,我们有时候会删去最左边的元素,有时候会删去最右边的元素,但是这种情况太复杂了,我们要转换思路。

正难则反:

题目要求我们找到数组两边使x值减为0的最小个数,我们就可以转换为求中间和为sum-x的最长子串。

解法一:暴力枚举

套两层for循环,遍历每一个子数组的情况,根据子数组的和是否等于target的值,我们就更新结果,接着break跳出一层循环。

解法二:滑动窗口

我们通过滑动窗口来优化枚举,我们每进行一次新的遍历的时候,我们发现没必要每次都让right回到left的位置,因为数组里面都是正数,当left++之后,[left,right]区间的和肯定是小于target的。

此时,发现left和right指针都不回退,此时就可以使用滑动窗口。

1.进窗口:tmp+=nums[right]

2.判断+出窗口:判断tmp的值是否大于target,如果大于出窗口,即nums-=nums[left++]

3.更新结果:当tmp的值等于target的时候,我们就可以更新结果。

java 复制代码
//时间复杂度:O(n)
//空间复杂度:O(1)
    public int minOperations(int[] nums, int x) {
        int sum=0;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
        }
        int ret=-1;
        int target=sum-x;
        //处理细节,
        if(target<0) return -1;
        for(int left=0,right=0,tmp=0;right<nums.length;right++){
            tmp+=nums[right];//进窗口
            while(tmp>target){//判断
                tmp-=nums[left++];//出窗口
            }
            if(tmp==target){
                ret=Math.max(ret,right-left+1);//更新结果
            }
        }
        if(ret==-1) return -1;//此时没有找到子数组和为target的子数组
        else return nums.length-ret;
    }

5.水果成篮(从这里开始比较认真)

题目连接:904. 水果成篮 - 力扣(LeetCode)

题目分析:有一个fruit数组,在数组中,不同元素的值代表不同的水果种类,相同元素的值代表水果的种类相同,我们有两个篮子,每个篮子只能装一种水果,一个篮子中装的水果数量没有限制。如果摘水果的过程中,一旦遇到与篮子中水果种类不同的水果树,就停止采摘,求这两个篮子能装的最大水果数量。

以上可以总结为一句话:找一个连续的最长子数组,该子数组中的水果种类不超出两种。

解法一:暴力枚举+哈希表

我们可以将每一个子数组的情况枚举出来,枚举的过程中,我们可以借助一个hash表来保存枚举过程中采摘水果的种类和数量。

我们用left为外层循环的标志,right为内层循环的标志

枚举的小细节:

  1. 为了防止在[1,2,1]的情况下,right指针会造成数组越界,所以我们每次进行一次内循环时,要对right指针进行判断,是否越界。

2.当篮子中水果的种类也超出两种时,也应该跳出该内层循环

3.在每一次采摘水果之前,必须判断水果种类为2种时,下次采摘的水果是否为第三种水果,如果成立,则跳出内部循环

4.每次进行一次新的外部枚举时,我们也要将hash表中上次枚举保存水果的情况删掉。

代码

java 复制代码
//空间复杂度:O(n)
//时间复杂度:O(n^2)
    public int totalFruit(int[] f) {
        Map<Integer, Integer> hash = new HashMap<Integer, Integer>();
        int ret = 0;
        for (int left = 0; left < f.length; left++) {
            for (int right = left; right < f.length; right++) {
                if (right == f.length || hash.size() > 2) {//判断数组是否越界和水果种类的数量
                    break;
                }
                int in = f[right];
                if (hash.size() == 2 && !hash.containsKey(in)) {//摘水果之前的判断
                    break;
                }
                hash.put(in, hash.getOrDefault(in, 0) + 1);
                ret = Math.max(ret, right - left + 1);
            }
            hash.clear();//在下次枚举之前,删除此次枚举的情况
        }
        return ret;
    }

解法二:滑动窗口

当我们进行新的left的枚举时,我们没必要让right重新回到left的位置,因为当left进行新的枚举时(left往后走),如果right重新返回到left指针的位置,往后枚举的时候,right会出现两种情况,第一种情况:right会停在在上一次left枚举时,right的最后枚举的位置或者超过****right最后枚举的位置。也就是说,以新的left为新的起点,进行right的枚举时,right是一定会经过之前的枚举停下的位置的,所以,我们就不必要将right返回到left的位置。

通过上面的分析,发现left和right指针是同向双指针,这时我们就可以使用滑动窗口来解决这个问题。

解题步骤

1.定义left=0,right=0

2.进窗口:让hash[f[right]]++

3.判断+出窗口(一个循环):

当hash.size>2时,让hash[f[left]]--,同时让left++

4.更新长度

用哈希表来实现:

java 复制代码
//时间复杂度:O(n)
//空间复杂度:O(n)
    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;
    }

用数组来实现:

java 复制代码
    public int totalFruit(int[] f) {
        int n=f.length;
        int[] hash=new int[n+1];
        int ret=0;
        for(int left=0,right=0,kind=0;right<n;right++){
            int in=f[right];
            if(hash[in]==0){
                kind++;
            }
            hash[in]++;//进窗口
            while(kind>2){//判断
                int out=f[left];
                hash[out]--;//出窗口
                if(hash[out]==0){
                    kind--;
                }
                left++;
            }
            ret=Math.max(ret,right-left+1);//更新长度
        }
        return ret;
    }

6.找出字符串中所有的异位字符串

题目链接:438. 找到字符串中所有字母异位词 - 力扣(LeetCode)

题目解析:再s字符串中找出p字符串中的所有异位字符串

异位字符串就是相同字符但是字符的顺序不一样组成的字符串,如abc、acb、bac、bca、cab和cba都是abc的异位字符串。

解决思路:滑动窗口+哈希表

如何判断两个字符串互为异位字符串呢?

第一种方法:我们可以将两个字符串按字典的顺序进行排序,接着判断这两个字符串是否相同就行,如果相同,那么就是异位字符串,如果不同,则不是异位字符串。

第二种方法:借用两个哈希表,hash1来存储p字符串,hash2来存储s字符串,最终判断两个哈希表是否相同,如果相同,那么互为异位字符串,如果不同,则不是异位字符串。

以下图为例

我们在s中找p的异位字符串,我们使用暴力枚举时,第一次枚举时, 当right-left+1长度为p.length()时,第一次枚举就结束了,如下图

此时第一次枚举就结束了,进行第二次枚举,让left++,同时让right返回到left的所处的位置

进行第二次枚举时,right继续走向right-left+1=p.length()的位置,此时发现right依然会进过之前的字符b和字符a

所以,每一次进行新的枚举,没必要让right回到left的位置,这样left和right都是同向双指针,这时,我们就可以用滑动窗口来解决问题。

进窗口:当right-left+1<=s.length时,hash2[in]++

判断+出窗口

如果right-left+1>p.length(),就出窗口,让hash2[out]--,同时让left++

更新结果

要判断是异位字符串在更新结果

代码实现

java 复制代码
//时间复杂度:O(n+m)
//空间复杂度:O(n+m)
    public List<Integer> findAnagrams(String ss, String pp) {
        List<Integer> ret=new ArrayList<>();
        char[] s=ss.toCharArray();
        char[] p=pp.toCharArray();
        int[] hash1=new int[26];
        int[] hash2=new int[26];
        for(char ch:p){
            hash1[ch-'a']++;
        }
        for(int left=0,right=0;right<s.length;right++){
            char in=s[right];
            hash2[in-'a']++;//进窗口
            if(right-left+1>p.length){//判断
                char out=s[left];
                hash2[out-'a']--;//出窗口
                left++;
            }
            //更新结果
            if(right-left+1==p.length){//判断是否互为异位字符串
                boolean flag=true;
                for(int i=0;i<26;i++){
                    if(hash1[i]!=hash2[i]){
                        flag=false;
                    }
                }
                if(flag==true)  ret.add(left);//更新结果
            }
        }
        return ret;
    }

进一步优化,此时我们可以在更新结果那里优化一下,因为在更新结果那里我们需要遍历两个哈希表,时间复杂度还是太大了,我们可以通过一个变量count统计窗口中的有效字符个数。

下图解释了什么是有效字符,一次类推

前面我们用hash1统计了字符串p中的情况,用hash2统计了字符串s中的情况。

进窗口之后,我们对hash1[in]和hash2[in]进行比较,如果hash2[in]小于等于hash1[in],那么此时就可以认为该字符是一个有效字符,让count++

出窗口之前,我们对hash1[out]和hash2[out]进行比较,如果hash2[out]小于等于hash[out],此时就可以认为出去的字符是一个有效字符,让count--

最终在更新结果的时候,我们只要判断count是否等于p.length,如果等于p.length,就更新结果,如果不等于p.length,就不更新结果。

代码实现

java 复制代码
       public List<Integer> findAnagrams(String ss, String pp) {
        List<Integer> ret=new ArrayList<>();
        char[] s=ss.toCharArray();
        char[] p=pp.toCharArray();
        int[] hash1=new int[26];
        int[] hash2=new int[26];
        for(char ch:p){
            hash1[ch-'a']++;
        }
        for(int left=0,right=0,count=0;right<s.length;right++){
            char in=s[right];
            hash2[in-'a']++;//进窗口
            if(hash2[in-'a']<=hash1[in-'a']) count++;//更新有效字符个数
            if(right-left+1>p.length){//判断
                char out=s[left];
                if(hash2[out-'a']<=hash1[out-'a']) count--;//更新有效字符个数
                hash2[out-'a']--;//出窗口
                left++;
            }
            //更新结果
            if(count==p.length) ret.add(left);
        }
        return ret;
    }

7.串联所有单词的子串

题目链接:30. 串联所有单词的子串 - 力扣(LeetCode)

我们如果将words的每一个字符串看成一个整体,在以这个整体为单位去在s中找串联所有单词的子串,这时就跟找异位字符串差不多了。如下图

这道题的思路和第6题的解题思路差不多,这里讲不同点,假设words数组字符串的长度为m,数组的长度为len

1.right和left指针的位移

right和left一次位移的长度为m

2.hash表的不同

这里的哈希表存的是字符串的种类和数量,即Hash<String,Integer>

3.进行滑动窗口的次数

次数为m次

这里对不同点3进行解释

代码实现:

java 复制代码
    public List<Integer> findSubstring(String s, String[] words) {
        Map<String,Integer> hash1=new HashMap<String,Integer>();//存储words
        List<Integer> ret=new ArrayList<Integer>();
        for(String str:words){
            hash1.put(str,hash1.getOrDefault(str,0)+1);
        }
        int len=words[0].length(), m=words.length;
        for(int i=0;i<len;i++){
            //执行滑动窗口
            Map<String,Integer> hash2=new HashMap<String,Integer>();//存储s
            for(int left=i,right=i,count=0;right+len<=s.length();right+=len){
                String in=s.substring(right,right+len);
                hash2.put(in,hash2.getOrDefault(in,0)+1);
                if(hash2.get(in)<=hash1.getOrDefault(in,0)) count++;
                //判断+出窗口
                while(right-left+1>m*len){
                    String out=s.substring(left,left+len);
                    if(hash2.get(out)<=hash1.getOrDefault(out,0)) count--;
                    hash2.put(out,hash2.getOrDefault(out,0)-1);
                    left+=len;
                }
                //更新结果
                if(count==m) ret.add(left);
            }
        }
        return ret;
    }

8.最小覆盖子串

题目链接:76. 最小覆盖子串 - 力扣(LeetCode)

题目分析:我们需要再字符串s中找一个子串,在这个子串中的字符种类,需要包含字符串t中所有字符类型,如果t中有了重复的字符,那么从s中找的子串的该字符的数量必须大于等于t中的重复字符的数量。

比如t为aba,那么在s中找的子串中,字符a的数量是不能小于t中a的字符数量。

解题思路:

首先,我们还是想到暴力枚举+hash表,我们将字符串中s的字符都枚举一遍,在枚举的过程中,如果遇到符合题目要求的子串,此时,就更新结果,接着立刻换一个字符进行新的枚举,以此类推下去。

优化思路:滑动窗口

如下图

此时,我们需要让left往后移动一步,当left++之后,left和right之间就会出现两种情况。

第一种情况:

如果left++之后,left和right之间的字符种类没有发生变化,当我们让right回到left的位置,进行新的枚举时,right还是会回到原来的位置。如下图

第二种情况:

如果left++之后,left和right之间的字符种类发生变化,当我们让right回到left的位置时,进行新的枚举,为了找到新的符合题目要求的子串,此时right肯定时跑到原来位置的后面。如下图:

所以,我们发现没必要每次都要将right返回到原来left的位置,我们只要根据每次left移动后的情况,根据情况来让right不动或者往后移动。

此时,发现left和right都是同向双指针,此时就可以使用滑动窗口。

在使用滑动窗口前,我们要用到两个哈希表,一个用来存储s字符串的情况,另一个用来存储t字符串的情况。

进窗口:hash2[in]++

判断+更新结果+出窗口:

判断:在s中找的子串是否符合题目要求,也就是hash2与hash1对应字符的数量是否一 样

跟新结果:由于我们这里找到一个符合题目要求的子串就要跟新结果,所以此处的跟新结果实在出窗口之前

出窗口:hash2[out]--

在进一步优化:更新结果

在更新结果那里,我们需要遍历两个哈希表来判断找的子串是否符合题目要求,每个哈希表都要遍历一遍,时间复杂度还是太大了,此时,我们可以通过count变量来统计hash1和hash2中完全相同的字符数量。

这里的完全相同是指数量和种类都相同。

在进窗口之后,如果hash2[in]==hash1[in],那么,我们认为在in在hash1和hash2中是完全相同的字符,则让count++

出窗口之前,如果如果hash2[in]==hash1[in],那么,我们认为在in在hash1和hash2中是完全相同的字符,则让count--

此时判断条件就变为count==hash1.size().

代码实现:

java 复制代码
    public String minWindow(String ss, String tt) {
        char[] s=ss.toCharArray();
        char[] t=tt.toCharArray();
        int[] hash1=new int[128];//存储t
        int[] hash2=new int[128];//存储s;
        int kinds=0;//记录t中有效字符的种类
        for(char ch:t){
            if(hash1[ch]==0) kinds++;
            hash1[ch]++;
        }
        int minlen=Integer.MAX_VALUE, begin=-1;
        for(int left=0,right=0,count=0;right<s.length;right++){
            //进窗口
            char in=s[right];
            hash2[in]++;
            if(hash2[in]==hash1[in]) count++;
            //判断+更新+出窗口
            while(kinds==count){
                //更新结果
                if(right-left+1<minlen){
                    minlen=right-left+1;
                    begin=left;
                }
                //出窗口
                char out=s[left];
                if(hash2[out]==hash1[out]) count--;
                hash2[out]--;//出窗口
                left++;//维护窗口
            }
        }
        if(begin==-1) return new String();
        else return ss.substring(begin,begin+minlen);
    }
相关推荐
ALISHENGYA1 小时前
Python基础经典编程练习题(二),含答案
python·算法
robin_suli1 小时前
动态规划子序列问题系列一>最长递增子序列的个数
数据结构·算法·动态规划
赏你个麻辣烫儿1 小时前
日拱一卒(16)——leetcode学习记录:山脉数组峰值索引
学习·算法·leetcode
徐霞客3201 小时前
C语言实现八大排序算法
数据结构·c++·算法·排序算法
知恩呐1111 小时前
RANS(Reynolds-Averaged Navier-Stokes) 湍流模型类型
算法
努力学计算机的小白一枚1 小时前
力扣1049.最后一块石头的重量(01背包)之理解篇
算法·leetcode·代理模式
oVo5671 小时前
Rust 宏
开发语言·算法·rust
Cchengzu1 小时前
美团2024年春招第一场笔试【前端&移动端方向】
前端·c++·算法
hansel_sky2 小时前
题解 - 莱布尼茨三角形
数据结构·c++·程序人生·算法·面试
果汁分你一半l2 小时前
顺序表的使用,对数据的增删改查
算法