实习校招面试手撕代码真题题型7——滑动窗口

滑动窗口

思路: 连续 最大 长度 要想起滑动窗口

可以去看下这个up讲滑动窗口的视频,我就是看了他讲的,讲的很不错:滑动窗口【基础算法精讲 03】_哔哩哔哩_bilibili

1 最长不重复子串

3. 无重复字符的最长子串 - 力扣(LeetCode)

    public int lengthOfLongestSubstring(String s) {
       int n = s.length();
       //左指针
       int left = 0;
       //最长子串的长度
       int maxLen = 0;
        //定义map存放[left,right]区间中各个字符出现的个数
        HashMap<Character, Integer> map = new HashMap<>();
        for (int right = 0; right < n; right++) {
            //右指针指向的字符
            char rightChar = s.charAt(right);
            //存到map中,该字符出现的次数加1
            map.put(rightChar, map.getOrDefault(rightChar, 0) + 1);

            //map.get(rightChar) > 1 表示右字符在前面接上的字符串中已经出现过,
            //此时需要移动左指针
            while (map.get(rightChar) > 1){
                //左指针指向的字符
                char leftChar = s.charAt(left);
                //将左指针指向的字符在map中的个数减1
                map.put(leftChar, map.get(leftChar) - 1);
                //同时左指针左移一个单位
                left++;
            }
            //上述while之后,得到的[left,right]区间中的字符串是不重复的
            maxLen = Math.max(maxLen, right - left + 1);
        }
        return maxLen;
    }

2 长度最小的子数组

209. 长度最小的子数组 - 力扣(LeetCode)

public int minSubArrayLen20241016(int target, int[] nums) {
        int n = nums.length;
        int minLen = Integer.MAX_VALUE;
        int sum = 0;
        int left = 0;

        for (int right = 0; right < n; right ++){
            //加入当前right值到sum中
            sum += nums[right];

            //若此时sum大于target,则向右移动左指针尝试找到长度最小的总和大于等于target的子数组
            while (sum >= target){
                minLen = Math.min(minLen, right - left + 1);
                sum -= nums[left];
                left ++;
            }
        }
        return minLen == Integer.MAX_VALUE ? 0 : minLen;
    }

3 乘积小于 K 的子数组

713. 乘积小于 K 的子数组 - 力扣(LeetCode)

    public int numSubarrayProductLessThanK(int[] nums, int k) {
        if (k <= 1) return 0;
        int n = nums.length;
        //左指针
        int left = 0;
        //乘积初始化时要为1而不是0
        int sum = 1;
        //符合要求的数组个数
        int cnt = 0;

        for (int right = 0; right < n; right++) {
            sum *= nums[right];
            //当乘积大于等于k时,左指针右移,直到符合要求(乘积小于k)
            while (sum >= k){
                //当不符合要求时,左指针右移
                sum /= nums[left];
                left++;
            }
            //当右节点为right,此时符合要求的数组个数如下式
            cnt += right - left + 1;
        }
        return cnt;
    }

4 最长的连续绿色衣服士兵

题目(华为可信科目二):一队士兵排成一排,身穿绿色跟黑色衣服,如果可以随便将一个士兵移除队伍,那么求最长的连续绿色衣服的士兵队伍长度,示例:绿色表示1,黑色表示0

输入:10111

输出: 4

表示移出第二个位置的黑色士兵,最大连续长度为4.

public static int longestOnes(int[] nums){
    int n = nums.length;
    int cnt0 = 0; //表示滑动窗口里的0的个数
    int max1 = 0; //表示最大连续1的个数
    int left = 0; //左指针

    //最长可翻转1 也就是变成了求滑动窗口内0的数量小于等于1时最大滑动窗口大小
    for (int right = 0; right < n; right++) {
        int rNum = nums[right];
        if (rNum == 0) cnt0 ++;

        //当cnt0 滑动窗口左移
        while (cnt0 > 1){
            int lNum = nums[left];
            if (lNum == 0) cnt0 --;
            left ++;
        }

        max1 = Math.max(max1, right - left + 1);
    }

    return cnt0 == 1 ? max1 - 1 : max1;
}

5 最大连续1的个数|||

1004. 最大连续1的个数 III - 力扣(LeetCode)

思路:转换为求滑动窗口内0的个数小于等于k时,滑动窗口的最大长度

    public int longestOnes(int[] nums, int k) {
        //思路 转换成当cnt0 <= k时,滑动窗口长度最大值

        int n = nums.length;
        int cnt0 = 0; //表示当前滑动窗口内0的个数
        int maxlen = 0; //表示当前最长的滑动窗口
        int left = 0;

        for (int right = 0; right < n; right ++){
            int rNum = nums[right];
            if (rNum == 0) cnt0 ++;

            //若前面操作使得cnt0 > k,则需要让left右移,直到cnt0 <= k
            while (cnt0 > k){
                int lNum = nums[left];
                if (lNum == 0) cnt0 --;
                left ++;
            }
            //经上面操作后 cnt0 <= k
            //判断是否更新maxlen。 right - left + 1为当前滑动窗口大小与max1比较,取最大值
            maxlen = Math.max(maxlen, right - left + 1);
        }
        return maxlen;
    }

6 加油站

134. 加油站 - 力扣(LeetCode)

思路:目的 找到以left开始 长度为n的滑动窗口即是正确的流程,用rest来表示剩余油量

 public int canCompleteCircuit(int[] gas, int[] cost) {
        int n = gas.length;

        int rest = 0; //表示剩余汽油量 
        int left = 0; //左指针

        //目的 找到以left开始 长度为n的滑动窗口即是正确的流程
        for (int right = 0; right - left < n; right ++){
            rest += gas[right % n] - cost[right % n]; //因为right可能回调 从 4调到1

            //若当前滑动窗口 剩余油量小于0说明 不能以该left为起点 让left右移
            while (rest < 0 && left < n){
                rest -= gas[left] - cost[left];
                left ++;
            }

        }
        return rest >= 0 ? left : - 1;
    }

7 求字符串中同一字母连续出现的最大次数

题目描述: 给你一个字符串,只包含大写字母,求同一字母连续出现的最大次数。

例如”AAAABBCDHHH”,同一字母连续出现的最大次数为4,因为一开始A连续出现了4次。

ADDDDBDDDCAAAAAAA 7

这是本人一面手撕代码原题

public static int maxLX(String s){
        int n = s.length();
        int max = 0;
        int left = 0;
        char win = s.charAt(0); //初始 将滑动窗口内的字符设置为最左边的字符
        for (int right = 0; right < n; right++) {
            char rChar = s.charAt(right); 
            while (rChar != win){  //若右字符与滑动窗口内字符不一致 
                char lChar = s.charAt(left);
                if (lChar == win) left ++; //若当前左指针指向的字符和win相同 则让左指针右移
                else { //否则更新滑动窗口字符以及左指针位置
                    win = rChar;
                    left = right;
                }
            }
            max = Math.max(right - left + 1, max);
        }
        return max;
    }

8 找最大连续子串 (遇到换题)

题目(华为可信科目二):一串字符串由"1-10"“A-Z"组成,各字符之间由”"隔开,找到最大连续的子串。(10后面的字符是A)

输入:1,2,3,4,5,7,8 输出1 2 3 4 5

这题,我做了挺久但苦于没有输入输出用例,所以想着如果遇到了就换题

你可能感兴趣的:(#,面试,java,数据结构,leetcode,算法题,手撕代码,面试手撕)