• 算法通关村第16关【白银】| 滑动窗口经典问题


    1. 最长子串问题

    (1)无重复字符的最长子串

    思路:窗口内为无重复字符子串,使用哈希表来保存最新碰到的字符下标,只要出现重复就缩小left指针,缩小到无重复字符也就是map.get(c)+1

    1. class Solution {
    2. public int lengthOfLongestSubstring(String s) {
    3. HashMap map = new HashMap();
    4. int l = 0;
    5. int r = 0;
    6. int len = s.length();
    7. int res = 0;
    8. while(r
    9. char c = s.charAt(r);
    10. if(map.get(c) != null){
    11. l = Math.max(l,map.get(c) + 1);
    12. }
    13. map.put(c,r);
    14. res = Math.max(r-l+1,res);
    15. r++;
    16. }
    17. return res;
    18. }
    19. }

    (2)至多包含两个不同字符的最长子串

    思路:窗口为两个以内的不同字符,使用哈希表来保存最新碰到的字符下标,和上一题不同的是这里需要关注哈希表的size,如果超过2代表窗口内有两个以上不同的字符了,需要更新left指针位置为记录的窗口内最小的位置,并移除

    1. public static int lengthOfLongestSubstringTwoDistinct(String s) {
    2. if (s.length() < 3) {
    3. return s.length();
    4. }
    5. int left = 0, right = 0;
    6. HashMap hashmap = new HashMap<>();
    7. int maxLen = 2;
    8. while (right < s.length()) {
    9. if (hashmap.size() < 3)
    10. hashmap.put(s.charAt(right), right++);
    11. // 如果大小达到了3个
    12. if (hashmap.size() == 3) {
    13. // 最左侧要删除的位置
    14. int del_idx = Collections.min(hashmap.values());
    15. hashmap.remove(s.charAt(del_idx));
    16. // 窗口left的新位置
    17. left = del_idx + 1;
    18. }
    19. maxLen = Math.max(maxLen, right - left);
    20. }
    21. return maxLen;
    22. }

    (3)至多包含k个不同字符的最长子串

    题目:给定一个字符串 s,找出 至多 包含 k 个不同字符的最长子串T

    思路:只需要将上一题的3改成k,完美移植

    1. public static int lengthOfLongestSubstringKDistinct(String s, int k) {
    2. if (s.length() < k + 1) {
    3. return s.length();
    4. }
    5. int left = 0, right = 0;
    6. HashMap hashmap = new HashMap<>();
    7. int maxLen = k;
    8. while (right < s.length()) {
    9. if (hashmap.size() < k + 1)
    10. hashmap.put(s.charAt(right), right++);
    11. // 如果大小达到了k个
    12. if (hashmap.size() == k + 1) {
    13. //
    14. int del_idx = Collections.min(hashmap.values());
    15. hashmap.remove(s.charAt(del_idx));
    16. // 窗口left的新位置
    17. left = del_idx + 1;
    18. }
    19. maxLen = Math.max(maxLen, right - left);
    20. }
    21. return maxLen;
    22. }

    2. 长度最小的子数组

    思路:当小于target时就不断扩大窗口,当大于等于target的时候就从l开始不断剔除元素

    1. class Solution {
    2. public int minSubArrayLen(int target, int[] nums) {
    3. int l = 0;
    4. int r = 0;
    5. int sum = 0;
    6. int min = Integer.MAX_VALUE;
    7. while(r
    8. sum += nums[r];
    9. while(sum>=target){
    10. min = Math.min(min,r-l+1);
    11. sum -= nums[l++];
    12. }
    13. r++;
    14. }
    15. return min!=Integer.MAX_VALUE ? min : 0;
    16. }
    17. }

    3.盛水最多的容器

    思路:这题和上面不同的地方在于,不是双指针从头开始慢慢增大窗口,而是从首尾开始缩小窗口

    长板不动,因为长板往内移动是一定会变小容量的

    短板内移,可能变大也可能变小还可能不变,遍历一遍取最大

    1. class Solution {
    2. public int maxArea(int[] height) {
    3. int left = 0;
    4. int right = height.length-1;
    5. int low = Math.min(height[left],height[right]);
    6. int ability = 0;
    7. while(right > left){
    8. if(height[left]
    9. ability = Math.max(ability,(right-left)*height[left]);
    10. left++;
    11. }else{
    12. ability = Math.max(ability,(right-left)*height[right]);
    13. right--;
    14. }
    15. }
    16. return ability;
    17. }
    18. }

    4.寻找子串异位词

    1)字符串的排列

    思路:窗口为子串大小,从s1的位置为初始窗口位置开始遍历,看看s2窗口内是不是与s1相等的

    1. class Solution {
    2. public boolean checkInclusion(String s1, String s2) {
    3. if(s1.length()>s2.length()){
    4. return false;
    5. }
    6. char[] c1 = new char[26];
    7. char[] c2 = new char[26];
    8. int left = 0;
    9. int right = s1.length();
    10. for(int i = 0;i
    11. c1[s1.charAt(i)-'a']++;
    12. c2[s2.charAt(i)-'a']++;
    13. }
    14. if(Arrays.equals(c2,c1)){
    15. return true;
    16. }
    17. for(;right
    18. c2[s2.charAt(right)-'a']++;
    19. c2[s2.charAt(left)-'a']--;
    20. left++;
    21. if(Arrays.equals(c2,c1)){
    22. return true;
    23. }
    24. }
    25. return false;
    26. }
    27. }

    2)找到字符串中所有字母异位词

    思路:和上一题差不多,窗口为子串大小,从子串大小位置为初始窗口位置开始遍历

    1. class Solution {
    2. public List findAnagrams(String s, String p) {
    3. if(s.length()
    4. return new ArrayList<>();
    5. }
    6. char[] c1 = new char[26];
    7. char[] c2 = new char[26];
    8. int left = 0;
    9. int right = p.length();
    10. for(int i = 0;i
    11. c1[p.charAt(i)-'a']++;
    12. c2[s.charAt(i)-'a']++;
    13. }
    14. List list = new ArrayList<>();
    15. if(Arrays.equals(c2,c1)){
    16. list.add(0);
    17. }
    18. while(right
    19. c2[s.charAt(right)-'a']++;
    20. c2[s.charAt(left)-'a']--;
    21. left++;
    22. if(Arrays.equals(c2,c1)){
    23. list.add(left);
    24. }
    25. right++;
    26. }
    27. return list;
    28. }
    29. }

  • 相关阅读:
    小程序中的权限设计
    基于 golang 从零到一实现时间轮算法 (三)
    java毕业设计员工绩效考核系统分析与设计Mybatis+系统+数据库+调试部署
    ScheduledThreadPoolExecutor 类
    C语言:两个数的交换函数
    Linux内核完全注释(基于Linux0.11)_笔记_Linux0.11执行流程
    Happy 1024
    通知可以根据切入点表达式来进行增强,也可以根据自己的注解值来进行增强
    如何在WPF网格中隐藏行
    4. git 添加版本标签
  • 原文地址:https://blog.csdn.net/Candy___i/article/details/133236749