最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java滑動(dòng)窗口算法題目練習(xí)(附詳細(xì)圖文及代碼)

 更新時(shí)間:2025年10月19日 11:01:42   作者:代碼不停  
在數(shù)據(jù)處理和算法中,滑動(dòng)窗口是一種常見的技術(shù),用于解決一些數(shù)組或字符串相關(guān)的問(wèn)題,這篇文章主要介紹了Java滑動(dòng)窗口算法題目練習(xí)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

長(zhǎng)度最小的子數(shù)組

題目解析:這里給我們一個(gè)全是正整數(shù)的數(shù)組和一個(gè)目標(biāo)值,讓我們找一段連續(xù)的區(qū)間,這個(gè)區(qū)間的值之和是大于等于目標(biāo)值的,從這個(gè)數(shù)組中找到一個(gè)最小的區(qū)間長(zhǎng)度,如果不存在的話就返回0
算法原理:1.首先我們是可以使用暴力解法,雙重for循環(huán)進(jìn)行遍歷出所有的情況,當(dāng)滿足區(qū)間的值大于等于目標(biāo)值的話就進(jìn)行結(jié)果更新,反之繼續(xù)向后操作,我們可以發(fā)現(xiàn)這里是有許多的是多余的,就像如果此時(shí)的這個(gè)區(qū)間的值已經(jīng)大于這個(gè)目標(biāo)值了,如果繼續(xù)向后操作的話,這個(gè)數(shù)組是正整數(shù)數(shù)組,肯定還是大于等于目標(biāo)值,但是長(zhǎng)度變長(zhǎng)了,我們要找到是最短的,因此我們可以不需要讓其重復(fù)操作,直接開始下一次循環(huán)就行
2."同向雙指針"也叫滑動(dòng)窗口算法,這里我們可以使用left和right兩個(gè)指針向同一個(gè)方向移動(dòng),并且不回退,此時(shí)的思想就和上面暴力解法優(yōu)化思想一樣,一直進(jìn)行將right下標(biāo)對(duì)應(yīng)的值放入sum變量中,當(dāng)sum>=target時(shí)候就可以將minlen更新了,此時(shí)不必將right向后移動(dòng)了,只需要將left下標(biāo)的值減去,讓left向后移動(dòng),這樣重復(fù)操作進(jìn)行查找,直到right遍歷完整個(gè)數(shù)組就完成了

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int sum = 0;
        int len = Integer.MAX_VALUE;//剛開始定義長(zhǎng)度是int可以表示最大整數(shù)
        int n = nums.length;
        for(int left = 0,right = 0; right < n;right++){
            sum += nums[right];//入窗口
            //結(jié)果判斷
            while(sum >= target){
                len = Math.min(len , right - left + 1);//結(jié)果更新
                sum -= nums[left++]; //出窗口
            }
        }
        return len == Integer.MAX_VALUE ? 0 : len;
    }
}

時(shí)間復(fù)雜度:O(N),空間復(fù)雜度:O(1)

無(wú)重復(fù)字符的最長(zhǎng)子串

題目解析:這里就是給了我們一個(gè)字符串s,讓我們?cè)诶锩嬲页?strong>最長(zhǎng)連續(xù)不重復(fù)的子串長(zhǎng)度,如果是空字符串就返回0
算法原理:1.暴力解法+哈希表(判斷字符是否重復(fù)出現(xiàn)),就是將其字符串中所有情況全部遍歷一遍,將其存放在哈希表中,遍歷的過(guò)程中判斷是否已經(jīng)存放在哈希表中,如果存在這時(shí)候就更新結(jié)果,并就跳出內(nèi)循環(huán),就這樣一直重復(fù)操作
2.滑動(dòng)窗口+哈希表,上面的暴力解法中會(huì)出現(xiàn)一些多余的操作,這里我們用left和right這兩個(gè)同向雙指針,不回退,right用來(lái)遍歷整個(gè)字符串并將其放入哈希表中,并當(dāng)right下標(biāo)的字符存放后發(fā)現(xiàn)其如果沒(méi)重復(fù)就更新結(jié)果 ,如果存在重復(fù),那肯定是此下標(biāo)有重復(fù)的,這時(shí)候就將left對(duì)應(yīng)的字符從哈希表中刪除,但我們可能要?jiǎng)h除很多次,因?yàn)槲覀儾⒉恢榔淠莻€(gè)是重復(fù)的,所以此時(shí)是個(gè)循環(huán),直到?jīng)]有重復(fù)為止繼續(xù)更新結(jié)果,就這樣一直right放入窗口,判斷是否有重復(fù)字符,有的話就一直出left到?jīng)]有重復(fù)字符為止,更新結(jié)果,就這樣一直到right遍歷完整個(gè)字符串

我們這里是使用int類型的數(shù)組來(lái)模擬哈希表,因?yàn)樽址麑?duì)應(yīng)的是ASCLL碼值

因此我們可以根據(jù)每次存放將其下標(biāo)的值++,大于1說(shuō)明有重復(fù)的就進(jìn)行出窗口 

class Solution {
    public int lengthOfLongestSubstring(String ss) {
        int[] hash = new int[128];//這里使用數(shù)組來(lái)表示其hash,如果其對(duì)應(yīng)的位置>1說(shuō)明有重復(fù)的
        int len = 0;
        char[] s = ss.toCharArray();//將其字符串轉(zhuǎn)換成字符數(shù)組,方便后面使用
        //使用同向雙指針,滑動(dòng)窗口
        for(int left = 0,right = 0;right < s.length;right++){
            //入窗口
            hash[s[right]]++;//字符對(duì)應(yīng)的ASCLL碼值作為下標(biāo)++
            //判斷,如果>1,說(shuō)明有重復(fù)的了,就要出窗口
            while(hash[s[right]] > 1){
                //出窗口
                hash[s[left++]]--;
            }
            //更新結(jié)果
            len = Math.max(len,right - left+1);
        }
        return len;
    }
}

最大連續(xù)1的個(gè)數(shù)|||

題目解析:題目就是找到最大連續(xù)1的個(gè)數(shù),并且最多可以反轉(zhuǎn)k個(gè)0
因此我們可以將其題目轉(zhuǎn)換成找出一個(gè)最長(zhǎng)子數(shù)組并且里面0的個(gè)數(shù)步超過(guò)k個(gè)
算法原理:1.暴力枚舉+count(記錄當(dāng)前區(qū)間0的個(gè)數(shù))
2.滑動(dòng)窗口+count(記錄當(dāng)前區(qū)間0的個(gè)數(shù))

class Solution {
    public int longestOnes(int[] nums, int k) {
        int len = 0;
        int n = nums.length;
        int count = 0;//用于統(tǒng)計(jì)當(dāng)前區(qū)間0的個(gè)數(shù)
        for(int left = 0,right = 0;right < n;right++){
            //記錄當(dāng)前0的個(gè)數(shù)
            if(nums[right] == 0){
                count++;
            }
            //出窗口
            while(count > k){
                if(nums[left++] == 0){
                    count--;
                }
            }
            //更新結(jié)果
            len = Math.max(len , right - left + 1);
        }
        return len;
    }
}

時(shí)間復(fù)雜度:O(N),空間復(fù)雜度:O(1)

將x減到0的最小操作數(shù)

題目解析:就是給了我們一個(gè)目標(biāo)值x讓我們每次從nums數(shù)組最左邊或者最右邊找一個(gè)數(shù),將其減去,減去就要從數(shù)組中移除這個(gè)數(shù),就這樣一直重復(fù)操作,找出一個(gè)最小操作數(shù),我們可以發(fā)現(xiàn)這個(gè)問(wèn)題十分繁瑣,因?yàn)槲覀兠看我膊恢钡绞菑淖筮呥€是右邊
因此我們可以正難則反 我們可以將題目轉(zhuǎn)換為在這個(gè)數(shù)組連續(xù)區(qū)間找一個(gè)最長(zhǎng)的長(zhǎng)度和為 整個(gè)數(shù)組的和 - x,最后返回?cái)?shù)組長(zhǎng)度 - 找到的長(zhǎng)度就行
算法原理:首先算出總的數(shù)組和sum ,我們的目標(biāo)值target = sum - x,我們直接從數(shù)組中找出一個(gè)最長(zhǎng)長(zhǎng)度區(qū)間,使其值等于target
這里找到target目標(biāo)值是采用滑動(dòng)窗口即同向雙指針,我們使用left和right兩個(gè)指針,right遍歷整個(gè)數(shù)組,total記錄當(dāng)前區(qū)間的值,
當(dāng) total == target時(shí)候就更新結(jié)果
當(dāng)total > target就出窗口,刪除left下標(biāo)的值,并讓left++,直到total <= target為止
反之就是小于,就一直將right下標(biāo)的值入窗口

class Solution {
    public int minOperations(int[] nums, int x) {
        //這里采用正難則反的思想,我們是每次從最右邊和最左邊找數(shù)相加,看何時(shí)等于x
        //我們可以轉(zhuǎn)換為在這個(gè)數(shù)組連續(xù)區(qū)間找一個(gè)最長(zhǎng)的長(zhǎng)度和為 整個(gè)數(shù)組的和 - x
        int sum = 0;//nums整個(gè)數(shù)組的和
        int n = nums.length;
        for(int i = 0; i < n;i++){
            sum += nums[i];
        }
        //此時(shí)我們的目標(biāo)值變成sum - x
        int target = sum - x;
        //如果全部sum和都<x說(shuō)明找不到
        if(target < 0){
            return -1;
        }
        int total = 0;
        int len = -1;
        //后面就使用滑動(dòng)窗口來(lái)找最長(zhǎng)子串使其長(zhǎng)度等于target目標(biāo)值
        for(int left = 0,right = 0;right < n;right++){
            //入窗口
            total += nums[right];
            //判斷
            while(total > target){
                total -= nums[left++];//出窗口
            }
            //等于的時(shí)候才更新結(jié)果
            if(total == target){
               len =  Math.max(len,right - left + 1);
            }
        }
        return len == -1 ? -1 : n - len;
    }
}

水果成藍(lán)

題目解析:就是給我們一個(gè)fruits數(shù)組,里面又好多種類,讓我們用兩個(gè)籃子放水果,并且每個(gè)籃子只能放一種水果,并且不可以跳著摘水果,遇到第三種水果直接停止采摘,獲取其中最多摘多少水果
問(wèn)題可以轉(zhuǎn)換為:找出一個(gè)最長(zhǎng)的子數(shù)組,并且里面不超過(guò)兩種水果
算法原理暴力解法+hash,可以使用雙重for循環(huán)進(jìn)行遍歷,left和right這兩個(gè)變量,但是其中有一些多余的操作,例如當(dāng)水果的種類大于2時(shí),我們此時(shí)采用的是,讓left++,right回到left的位置繼續(xù)進(jìn)行遍歷,但是我們可以發(fā)現(xiàn),原本[left,right]這個(gè)區(qū)間種類>2,讓其回去,此時(shí)讓left++,其中的中類要么不變,要么減小,肯定不會(huì)增加
滑動(dòng)窗口+hash
先不斷的將right下標(biāo)放入hash中
當(dāng)種類>2的時(shí)候就要出窗口left下標(biāo)對(duì)應(yīng)的水果數(shù)量–,當(dāng)其是0的時(shí)候說(shuō)明其種類減少,將其從hash中刪除,left++
更新結(jié)果
len = Math.max(len,right - left+1)

class Solution {
    public int totalFruit(int[] fruits) {
        //此時(shí)我們使用一個(gè)數(shù)組來(lái)實(shí)現(xiàn)hash
        int n = fruits.length;
        int[] hash = new int[n+1];
        int len = 0;//最長(zhǎng)的長(zhǎng)度
        for(int left = 0,right = 0,kinds = 0;right < n ;right++){
            //入窗口
            if(hash[fruits[right]] == 0){
                kinds++;//如果這個(gè)窗口沒(méi)有添加過(guò)這個(gè)元素,此時(shí)種類增多
            }
            hash[fruits[right]]++;
            //當(dāng)kinds>2進(jìn)行出窗口
            while(kinds > 2){
                //出窗口
                hash[fruits[left]]--;
                //此時(shí)如果這個(gè)連續(xù)的區(qū)間沒(méi)有了這個(gè)元素,此時(shí)的種類就減小
                if(hash[fruits[left]] ==0){
                    kinds--;
                }
                left++;
            }
            //更新結(jié)果
            len = Math.max(len,right - left + 1);
        }
        return len;
    }
}

時(shí)間復(fù)雜度:O(N)
空間復(fù)雜度:O(N)

找到字符串中所有字母異位詞

字母異位詞是通過(guò)重新排列不同單詞或短語(yǔ)的字母而形成的單詞或短語(yǔ),并使用所有原字母一次。

題目解析:就是給我們s和p兩個(gè)字符串,讓我們?cè)賡中找到所有p的異位詞子串,并將其索引,最后返回其中所有的索引
算法原理:首先我們想到的是暴力解法+hash,一直遍歷s串中所有和p長(zhǎng)度相同的子串,并且要同過(guò)hash比較其中是否相同,相同就將其下標(biāo)放入一個(gè)集合中,但是仍有一些多余的部分
滑動(dòng)窗口+hash:left = 0,right = 0
使用left和right來(lái)確定窗口,并且此時(shí)的窗口長(zhǎng)度是一定的,不斷讓right向后走,left也想后走,right并不需要回頭,因?yàn)槲覀円M(jìn)入下一個(gè)窗口僅需將left下標(biāo)對(duì)應(yīng)的字符出hash,將right+1下標(biāo)入hash就行,此時(shí)就進(jìn)入下一個(gè)窗口,讓后進(jìn)行判斷是否相同就行

class Solution {
    public List<Integer> findAnagrams(String ss, String pp) {
        List<Integer> ret = new ArrayList<>();

        char[] s = ss.toCharArray();
        char[] p = pp.toCharArray();
        //使用兩個(gè)數(shù)組來(lái)模擬hash
        int[] hash1 = new int[26];//用來(lái)放pp字符串的所有字符信息
        for(char ch : p){
            hash1[ch - 'a']++;
        }
        int[] hash2 = new int[26];//此時(shí)的用來(lái)放窗口中每個(gè)字符出現(xiàn)的次數(shù)
        int n = pp.length();
        //此時(shí)的count是用來(lái)統(tǒng)計(jì)有效字符個(gè)數(shù)
        for(int left = 0,right = 0,count = 0;right<ss.length();right++){
            char in = s[right];
            if(++hash2[in - 'a'] <= hash1[in - 'a']){//入窗口
                count++;
            }
            //判斷
            if(right - left + 1 > n){
                //出窗口
                char out = s[left++];
                if(hash2[out - 'a']-- <= hash1[out - 'a']){
                    count--;
                }
            }
            //更新結(jié)果
            if(count == n){
                ret.add(left);
            }
        }
        return ret;
    }
}

時(shí)間復(fù)雜度:O(N+M) ,兩個(gè)字符串串長(zhǎng)度
空間復(fù)雜度:O(N) , s字符串長(zhǎng)度

串聯(lián)所有單詞的子串

題目解析:就是在一個(gè)s字符串中找出包含words中所有單詞,并返回所有下標(biāo),
算法原理:此題目和上一題:找出所有字母的異位詞是一樣的意思,只不過(guò)我們此時(shí)這里的字母變成了單詞,因此這個(gè)題目和上一個(gè)原理一樣,只不過(guò)此時(shí)要注意將其單詞看成一個(gè)整體,這樣就和上一個(gè)題目一樣了

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        List<Integer> ret = new ArrayList<>();

        //使用map來(lái)存放words
        Map<String,Integer> hash1 = new HashMap<>();
        for(String word : words){
            hash1.put(word,hash1.getOrDefault(word,0)+1);
        }
        int n = words[0].length();//單詞長(zhǎng)度

        int m = words.length;//有多少單詞
        //此時(shí)要循環(huán)n次滑動(dòng)窗口,因?yàn)槲覀儗⒚總€(gè)單詞這些字符看成了一個(gè)整體放入hash
        for(int i = 0;i < n;i++){
            //使用count來(lái)統(tǒng)計(jì)有效單詞個(gè)數(shù)
            Map<String,Integer> hash2 = new HashMap<>();
            for(int left = i,right = i,count = 0;right <= s.length() - n;right += n){
                String in = s.substring(right,right+n);
                hash2.put(in,hash2.getOrDefault(in,0)+1);
                if(hash2.get(in) <= hash1.getOrDefault(in,0)){
                    count++;
                }

                //出窗口
                if(right - left + 1 > m*n){
                    String out = s.substring(left,left+n);
                    if(hash2.get(out) <= hash1.getOrDefault(out,0)){
                        count--;
                    }
                    hash2.put(out,hash2.get(out) - 1);
                    if(hash2.get(out) == 0){
                        hash2.remove(out);
                    }
                    left += n;
                }
                if(count == m){
                    ret.add(left);
                }
            }
        }
        return ret;
    }
}

時(shí)間復(fù)雜度:O( m * n)
空間復(fù)雜度:O( n )
n是words數(shù)組長(zhǎng)度,m是s的長(zhǎng)度

最小覆蓋子串

題目解析:在s這個(gè)字符串中找到一個(gè)最下子串,并且其中每個(gè)字母數(shù)量要不小于t中的
算法原理
暴力解法:雙重for循環(huán)+hash,雙重for循環(huán)遍歷所有情況,用hash存放,并有方法來(lái)判斷其是否符合條件
滑動(dòng)窗口+hash:left = 0 , right = 0;暴力解法中,我們遇到滿足情況進(jìn)行更新結(jié)果時(shí)候,其實(shí)并不需要將其right從新返回left,重新放入hash中,我們只需要將left下標(biāo)對(duì)應(yīng)字符出去就行,因?yàn)榇藭r(shí)只會(huì)出現(xiàn)兩種情況1.還滿足條件right不動(dòng)2.不滿足條件 right繼續(xù)右移

class Solution {
    public String minWindow(String ss, String tt) {
        char[] s = ss.toCharArray();
        char[] t = tt.toCharArray();

        //使用數(shù)組來(lái)模擬hash
        int[] hash1 = new int[128];
        int kinds = 0;//記錄tt中出現(xiàn)字符的種類
        for (char ch : t) {
            if (hash1[ch]++ == 0) {
                kinds++;
            }
        }

        int minlen = Integer.MAX_VALUE;
        int begin = -1;//記錄其起始位置和長(zhǎng)度即可
        int[] hash2 = new int[128];//記錄窗口中字符
        for (int left = 0, right = 0, count = 0; right < ss.length(); right++) {
            char in = s[right];
            //當(dāng)這個(gè)字符的數(shù)量和hash1相同時(shí)候,count++
            if (++hash2[in] == hash1[in]) {
                count++;
            }
            while (kinds == count) {
                //更新結(jié)果
                if (right - left + 1 < minlen) {
                    begin = left;
                    minlen = right - left + 1;
                }
                char out = s[left++];
                if (hash2[out]-- == hash1[out]) {
                    count--;
                }
            }
        }
        return begin == -1 ? new String() : ss.substring(begin, begin + minlen);
    }
}

時(shí)間復(fù)雜度:O(m + n)
空間復(fù)雜度:O(1)

點(diǎn)名

題目解析:就是一個(gè)遞增的數(shù)組,并且其下標(biāo)和其對(duì)應(yīng)的值是對(duì)應(yīng)的,

到此這篇關(guān)于Java滑動(dòng)窗口算法題目練習(xí)的文章就介紹到這了,更多相關(guān)Java滑動(dòng)窗口算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

甘谷县| 镇雄县| 惠安县| 平塘县| 鹰潭市| 清水县| 南溪县| 上饶市| 安溪县| 宣化县| 沾益县| 三穗县| 札达县| 上饶县| 正定县| 伊通| 阳春市| 武冈市| 商洛市| 鹿邑县| 蒙阴县| 湖口县| 上高县| 靖远县| 芜湖县| 龙里县| 故城县| 聂拉木县| 平潭县| 芒康县| 石家庄市| 邓州市| 彭山县| 图木舒克市| 崇文区| 隆昌县| 库尔勒市| 邹平县| 大渡口区| 桦甸市| 虹口区|