【题型总结】使用双指针+哈希表寻找符合某种条件的字符串/数字的个数
创始人
2024-03-21 16:33:56
0

文章目录

  • 双指针[滑动窗口]+哈希表
    • 变位词
      • 字符串中的排列【LC567】
      • 字符串中所有的变位词【LC438】
    • 不含重复字符的最长子字符串【LC3】
      • 哈希表+双指针
    • 含有所有字符的最短字符串/最小覆盖子串【LC76】
    • 字符串中不同整数的数目【LC1805】

双指针[滑动窗口]+哈希表

变位词

  • 定义

    变位词是指组成各个单词的字母及每个字母出现的次数完全相同,只是字母排列的顺序不同。如“pots”、“stop”和“tops”

  • 特点

    • 长度相同
    • 字母集合相同,并且每个字母出现的次数相同

字符串中的排列【LC567】

2022/10/27

给定两个字符串 s1s2,写一个函数来判断 s2 是否包含 s1 的某个变位词。

换句话说,第一个字符串的排列之一是第二个字符串的 子串

  • 思路:s1的字符在s2中全部存在,并且连续(子串),返回true

    • 记录第一出现的字符的位置和最后一个出现的字符的位置,如果相减长度为s1的长度,那么证明是连续出现的子串
      • 不对 字母可能多次出现 并且重复出现
    • 逐一判断字符串s2中长度为n的子字符串是不是字符串s1的变位词
  • 实现

    • 使用哈希表存储s1中出现的字符及其次数

    • 使用双指针定位一个子字符串,其中一个指针left指向子字符串的第一个字符,另一个指针指向子字符串的最后一个字符

      • 每当在子字符串中添加一个字符时,就把哈希表中对应位置的值减1
      • 每当在子字符串中删除一个字符时,就把哈希表中对应位置的值加1
    • 如果子字符串对应的charToCount全为0,那么证明该子字符串为字符串s1的变位词,返回true

    • 代码

      class Solution {public boolean checkInclusion(String s1, String s2) {if (s1.length() > s2.length()){return false;}int len1 = s1.length();int[] charToCount = new int[26];for (int i = 0; i < len1; i++){charToCount[s1.charAt(i)-'a']++;charToCount[s2.charAt(i)-'a']--;}if (areAllZeor(charToCount)){return true;}for (int i = len1; i < s2.length(); i++){charToCount[s2.charAt(i-len1)-'a']++;// 删除左指针对应的字符charToCount[s2.charAt(i)-'a']--;// 添加右指针对应的字符if (areAllZeor(charToCount)){return true;}}return false;}public boolean areAllZeor(int[] charToCount){for (int i = 0; i < charToCount.length; i++){if (charToCount[i] != 0){return false;}}return true;}
      }
      
    • 复杂度

      • 时间复杂度:O(n+m)O(n+m)O(n+m)
      • 空间复杂度:O(1)O(1)O(1)

字符串中所有的变位词【LC438】

2022/10/27

给定两个字符串 sp,找到 s 中所有 p变位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

变位词 指字母相同,但排列不同的字符串。

  • 思路:逐一判断字符串s中长度为lenP的子字符串是不是字符串p的变位词,如果是则将起始索添加至结果集

  • 实现

    • 使用哈希表存储p中出现的字符及其次数
    • 使用双指针定位一个子字符串,其中一个指针left指向子字符串的第一个字符,另一个指针指向子字符串的最后一个字符
      • 每当在子字符串中添加一个字符时,就把哈希表中对应位置的值减1
      • 每当在子字符串中删除一个字符时,就把哈希表中对应位置的值加1
    • 如果子字符串对应的charToCount全为0,那么证明该子字符串为字符串p的变位词,则将起始索添加至结果集
    • 最后返回结果集
  • 代码

    class Solution {public boolean checkInclusion(String s1, String s2) {if (s1.length() > s2.length()){return false;}int len1 = s1.length();int[] charToCount = new int[26];for (int i = 0; i < len1; i++){charToCount[s1.charAt(i)-'a']++;charToCount[s2.charAt(i)-'a']--;}if (areAllZeor(charToCount)){return true;}for (int i = len1; i < s2.length(); i++){charToCount[s2.charAt(i-len1)-'a']++;// 删除左指针对应的字符charToCount[s2.charAt(i)-'a']--;// 添加右指针对应的字符if (areAllZeor(charToCount)){return true;}}return false;}public boolean areAllZeor(int[] charToCount){for (int i = 0; i < charToCount.length; i++){if (charToCount[i] != 0){return false;}}return true;}
    }
    
    • 复杂度

      • 时间复杂度:O(n+m)O(n+m)O(n+m)
      • 空间复杂度:O(1)O(1)O(1)

不含重复字符的最长子字符串【LC3】

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

2022/10/27

哈希表+双指针

  • 思路:使用双指针定位一个子字符串,使用哈希表判断子字符串是否存在重复元素,如果有重复元素,当出现重复字符,收缩左边界直到重复字符消失

  • 实现

    • 使用哈希set存储目前存放的字符
    • 使用双指针定位一个子字符串,其中一个指针left指向子字符串的第一个字符,另一个指针指向子字符串的最后一个字符
      • 每当当前字符不位于哈希表中时,向右移动right
      • 每当当前字符位于哈希表中时,
        • 判断是否需要更新res,此时子字符串的长度为right-left
        • 然后向右移动left,找到重复的位置,并找到新的初始位置[每移动一次left,需要将对应的字符在哈希表中删除]
    • 最后返回结果
  • 代码 hashset

    class Solution {public int lengthOfLongestSubstring(String s) {Set words = new HashSet<>();int res = 0;int left = 0;int right = 0;while ( left <= right && right < s.length()){if (!words.contains(s.charAt(right))){words.add(s.charAt(right));}else{res = Math.max(res,right - left);while (left < s.length() && s.charAt(left) != s.charAt(right)){words.remove(s.charAt(left));left++;}left++;}right++;}res = Math.max(res,right - left);return res;}
    }
    
    • 复杂度
      • 时间复杂度:O(n)O(n)O(n)
      • 空间复杂度:O(1)O(1)O(1),hashset最大的容量为ASCII码的多少,为256
  • 代码 boolean数组

    class Solution {public int lengthOfLongestSubstring(String s) {boolean[] words = new boolean[256];int res = 0;int left = 0;int right = 0;while ( left <= right && right < s.length()){if (!words[s.charAt(right)]){words[s.charAt(right)] = true;}else{res = Math.max(res,right - left);while (left < s.length() && s.charAt(left) != s.charAt(right)){words[s.charAt(left)] = false;left++;}left++;}right++;}res = Math.max(res,right - left);return res;}
    }
    

含有所有字符的最短字符串/最小覆盖子串【LC76】

给定两个字符串 st 。返回 s 中包含 t 的所有字符的最短子字符串。如果 s 中不存在符合条件的子字符串,则返回空字符串 ""

如果 s 中存在多个符合条件的子字符串,返回任意一个。

注意: 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。

[可以包括其他字符的最短’变位词’]

2022/10/29

  • 思路:使用双指针定位s的子字符串,使用哈希表记录出现的字母及次数

    • 当该子字符串包含t的所有字符时,判断是否是最短子字符串,是则记录左右边界
    • 如果左边界出现重复字符并且不是所需要的字符,那么收缩左边界
  • 实现:

    • 使用哈希表存储t中出现的字符及其次数
    • 使用双指针定位一个子字符串,其中一个指针left指向子字符串的第一个字符,另一个指针right指向子字符串的最后一个字符
      • 每当在子字符串中添加一个字符时,就把哈希表中对应位置的值减1
      • 每当在子字符串中删除一个字符时,就把哈希表中对应位置的值加1
    • 如果子字符串对应的charToCounts全为0,那么证明该子字符串包含t的所有字符,判断是否是最短子字符串,是则记录左右边界
    • 最后返回判断是否存在子字符串,是则返回s.sbstring(left,right),否则返回空字符串
  • 代码

    class Solution {public String minWindow(String s, String t) {if (s.length() < t.length()){return "";}int[] charToCounts = new int['z'-'A'+1];int left = 0;int right = 0;int minLeft = 0;// 左闭右闭int minRight = Integer.MAX_VALUE;for (; right < t.length(); right++){charToCounts[t.charAt(right)-'A']++;charToCounts[s.charAt(right)-'A']--;}if (isContainsAll(charToCounts)){minRight = right - 1;}while (right < s.length()){charToCounts[s.charAt(right)-'A']--;// 左边界有重复字符或者不是所需字符 收缩左边界while (left <= right && charToCounts[s.charAt(left)-'A'] < 0){     charToCounts[s.charAt(left)-'A']++;left++;}if (isContainsAll(charToCounts)){// 包含全部字符if (right - left < minRight - minLeft){minRight = right;minLeft = left;}}right++;}return minRight == Integer.MAX_VALUE ? "" : s.substring(minLeft,minRight+1);}public boolean isContainsAll(int[] charToCounts){for(int i = 0; i < charToCounts.length; i++){if (charToCounts[i] > 0){return false;}}return true;}
    }
    
  • 复杂度

    • 时间复杂度:O(n)O(n)O(n)
    • 空间复杂度:O(C)O(C)O(C),charToCounts的容量为’z’-‘A’+1

字符串中不同整数的数目【LC1805】

You are given a string word that consists of digits and lowercase English letters.

You will replace every non-digit character with a space. For example, "a123bc34d8ef34" will become " 123 34 8 34". Notice that you are left with some integers that are separated by at least one space: "123", "34", "8", and "34".

Return the number of different integers after performing the replacement operations on word.

Two integers are considered different if their decimal representations without any leading zeros are different.

2022/12/6

  • 思路:使用双指针定位字符串中整数的起始位置和结束位置,去除前导0后,将该整数放入哈希表中,最后返回哈希表的大小即可。

    • 如果左指针为字母,那么右移左指针,左指针为整数的起始位置
    • 如果右指针为数字,那么右移右指针,右指针为整数的结束位置+1
  • 实现

    class Solution {public int numDifferentIntegers(String word) {Set set = new HashSet<>();int len = word.length();int l = 0;        int r = 0;while (l < len && r < len){// 找到左边界while (l < len && word.charAt(l) >= 'a' && word.charAt(l) <= 'z'){l++;}if (l == len){break;}// 找到右边界r = l;while ( r < len && word.charAt(r) >= '0' && word.charAt(r) <= '9') {r++;}// 去除前导0while (l != r && word.charAt(l) == '0'){l++;}String num = word.substring(l, r);set.add(num);l = r + 1;}return set.size();}
    }
    
    • 复杂度

      • 时间复杂度:O(n)O(n)O(n)
      • 空间复杂度:$

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...