• 【Leetcode-滑动窗口问题】


    在这里插入图片描述每一个不曾起舞的日子,都是对生命的辜负。

    Leetcode.3 无重复字符的最长子串

    给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

    示例 1:

    输入: s = “abcabcbb”
    输出: 3
    解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

    示例 2:

    输入: s = “bbbbb”
    输出: 1
    解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。

    示例 3:

    输入: s = “pwwkew”
    输出: 3
    解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
    请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

    提示

    • 0 <= s.length <= 5 * 104
    • s 由英文字母、数字、符号和空格组成

    来源:力扣(LeetCode)
    链接: 点我

    解法1:暴力求解

    思路:

    • 逐个生成子字符串
    • 看它是否不含有重复的字符
    • 时间复杂度O(N²)
    • 即:
      1. 定义一个right=0:外层循环中right表示遍历字符串,查找长度
      1. 定义一个left=0:内层循环中left表示判断从起始位置到right有没有重复元素,有则停止循环并改变起始条件,即left的内部循环起到判断作用。
      1. 定义一个cur,表示left的起始条件,因为如果出现重复字符,由于此时的left对应的元素与right对应的元素同,我们应该让cur = left+1,跳过这个重复的字符开始遍历。
      1. 定义一个count记录临时变量,定义一个max记录最大的count。

    在这里插入图片描述

    int lengthOfLongestSubstring(char* s)
    {
        if (s == NULL)
        {
            return 0;
        }
        int left = 0;
        int right = 0;
        int max = 0;
        int count = 0;
        int cur = 0;       //有重复元素时,定位left的起始位置
        int len = strlen(s);
        for (; right < len; right++)  //o(n)循环一遍字符串
        {
            count = 0;
            for (left = cur; left <= right; left++)  //right每移动一次,left就循环一遍检查有没有重复元素
            {
                count++;    //每次检查有没有重复元素,都计数一遍。
                if (s[left] == s[right] && left != right) //当出现相同元素时,两种情况,一种left==right,不做处理。left不等于right说明有重复元素,cur = left+1,让left下次循环跳过重复元素开始
                {
                    cur = left + 1;
                    break;
                }
            }
            if (count > max)
            {
                max = count;
            }
        }
        return max;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

    解法2:滑动窗口+哈希

    思路:

    • 重复字符 -->出现一次
    • 一旦涉及次数,哈希保存
    • 构造子串时记录长度利用滑动窗口
    1. 定义left,right为滑动窗口的左右边界
    2. 定义hash[127],数组的大小要比最大字符的ascii码值要大
    3. 定义max记录right-left的最大值

    遍历时有两种情况:

    1. s[right]重复出现:
      1. hash去掉left
      1. left+=1
      1. 更新max
    1. s[right]没出现过:
      1. hash加上right
      1. right+=1
      1. 更新max

    在这里插入图片描述

    int lengthOfLongestSubstring(char* s) {
        
        int hash[127] = { 0 };
        int left = 0;
        int right = 0;
        int max = 0;
    
        while (s[right]) {
            if (hash[s[right]]) {
                hash[s[left]] -= 1;
                left += 1;
            }
            else {
                hash[s[right]] += 1;
                right += 1;
            }
            max = max < (right - left) ? (right - left) : max;
        }
        return max;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    Leetcode.209 长度最小的子数组

    给定一个含有 n 个正整数的数组和一个正整数 target 。

    找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

    示例 1:

    输入:target = 7, nums = [2,3,1,2,4,3]
    输出:2
    解释:子数组 [4,3] 是该条件下的长度最小的子数组。
    示例 2:

    输入:target = 4, nums = [1,4,4]
    输出:1
    示例 3:

    输入:target = 11, nums = [1,1,1,1,1,1,1,1]
    输出:0

    提示:

    • 1 <= target <= 109
      1 <= nums.length <= 105
      1 <= nums[i] <= 105

    来源:力扣(LeetCode)
    链接: 点我

    解法1:暴力求解(会超出时间限制)

    即遍历所有可能的子串,时间复杂度为O(N²)

    int minSubArrayLen(int target, int* nums, int numsSize) {
        int i = 0;
        int j = 0;
        int sum = 0;
        int min = INT_MAX;
        for (i = 0; i < numsSize; i++)
        {
            sum = 0;
            for (j = i; j < numsSize; j++)
            {
                sum += nums[j];
                if (sum >= target)
                {
                    min = fmin(min, j - i + 1);
                    break;
                }
            }
    
        }
        if (min == INT_MAX)
            return 0;
        return min;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    解法2:滑动窗口

    思路:

    1. 定义[start,end]为滑动窗口区间
    2. 定义ans =INT_MAX,记录满足条件的元素长度
    3. 定义sum为滑动区间范围内的和

    定义一个窗口的边界[start,end],end不断向右移动,sum为这个区间范围内元素的和,当大于target时,将其存到返回值,并且窗口左侧开始向右滑动,随着滑动过程,不被窗口区间内所包含的左侧的数值需要减掉,同时start++,一直到sum

    int minSubArrayLen(int target, int* nums, int numsSize){
        int start = 0;
        int end = 0;
        int ans = INT_MAX;
        int sum = 0;
        while(end<numsSize)
        {
            sum+=nums[end];
            while(sum>=target)//不用if原因是有可能右侧的数过大导致减掉一个左侧的数之后sum仍然大于target
            {
                ans = fmin(ans,end-start+1);
                sum-=nums[start];
                start++;
            }
            end++;
        }
        return ans == INT_MAX? 0 : ans;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    总结:

    小伙伴们这是新的刷题专栏,这里以后会继续将有用的经验与方法分享出来,如果对你有所帮助的话,不要忘记三连支持呀!

  • 相关阅读:
    经验分享|甘肃某中型灌区信息化管理平台案例
    JavaWeb-Session和Cookie
    Mysql批量插入大量数据的方法
    PMI-ACP练习题(24)
    并查集路径压缩
    规则引擎(JVS-rules):从应用到场景的全面解析
    Docker+nginx部署Springboot+vue前后端分离项目(Linux版)
    JVM垃圾收集器总结
    MySQL数据库的索引和事务
    洛谷 P3397 地毯 Java实现 二维差分
  • 原文地址:https://blog.csdn.net/NEFUT/article/details/125996083