阅读 147

算法七 哈希表与字符串(Java实现)

任意元素的映射

利用哈希函数,将关键字值(key)(大整数、字符串、浮点数等)转换为整数再对表长取余,从而关键字值被转换为哈希表的表长范围内的整数。

拉链法解决冲突,构造哈希表

将所有哈希函数结果相同的结点连接在同一个单链表中。若选定的哈希表长度为m,则可将哈希表定义为一个长度为m的指针数组t[0..m-1], 指针数组中的每个指针指向哈希函数结果相同的单链表。

插入value:将元素value插入哈希表,若元素value的哈希函数值为hash_key,将value对应的节点以头插法的方式插入到以t[hash key]为头指针的单链表中。

查找value:若元素value的哈希函数值为hash_key,遍历以t[hash_ key]为头指针的单链表,查找链表各个节点的值域是否为value。

1、LeetCode409最长回文串

思路:1.利用字符哈希方法,统计字符串中所有的字符数量;

2.设置最长回文串偶数字符长度为max_ length = 0;

3.设置是否是否有中心点标记flag=0;

4.遍历每一个字符,字符数为count, 若count为偶数,max_ length += count;若count为奇数,max_ length += count-l, flag= 1;

5.最终最长回文子串长度: max_ length + flag。

class Solution {     public int longestPalindrome(String s) {         int[] char_map = new int[128];//字符哈希         int max_length = 0;//回文串偶数部分的最大长度         int flag = 0;//是否有中心点         for(int i=0;i<s.length();i++){             char c = s.charAt(i);             char_map[c]++;//利用整数的数组下标实现字符哈希,统计字符个数         }         for(int i=0;i<128;i++){             if(char_map[i]%2 == 0){//如果某字符为偶数个,则均可以使用在回文串里                 max_length += char_map[i];             }else{                 max_length += char_map[i]-1;//如果某字符为奇数个,则丢弃一个,其余的使用在回文串里                 flag = 1;//此时标记回文串可以有中心点             }         }         return max_length + flag;//最终结果是偶数部分的最大长度+中心点字符     } } 复制代码

2、LeetCode290单词规律

思路:1.设置单词(字符串)到pattern字符的映射(哈布);使用数组used[128]记录pattern字符是否使用。

2.遍历str,按照空格拆分单词,同时对应的向前移动指向pattern字符的指针,每拆分出一个单词,判断:

如果该单词从未出现在哈希表中:如果当前的pattern字符已被使用,则返回false;将单词与当前指向的attern字符做映射;标记当前指向的pattern字符已使用,否则:如果当前单词在哈希表中的映射字符不是当前指向的pattern字符,则返回false。

3.若单词个数与pattern字符个数不匹配,返回false。

LeetCode评论代码

class Solution {     public boolean wordPattern(String pattern, String s) {         String[] strings = s.split(" ");         if (pattern.length() != strings.length) {             return false;         }         HashMap<Object, Integer> hashMap = new HashMap<>();          //如果出现位置不匹配,或者一个已经出现而另一个没有出现过,则匹配失败。使用Objects.equals方法可以避免对null值进行判断         for (int i = 0; i < pattern.length(); i++) {             if(!Objects.equals(hashMap.put(pattern.charAt(i), i), hashMap.put(strings[i], i))){                 return false;             }         }         return true;     } } 复制代码

3、LeetCode49字母异位词分组

思路:设置字符串到字符串向量的哈希表anagram,遍历字符串向量strs中的单词strs[i]:

1)设置临时变量str = strs[i],对str进行排序。

2)若sr未出现在anagram中,设置str到一个空字符串向量的映射。

3)将strs[i]添加至字符串向量anagram[str]中。

遍历哈希表anagram,将全部key对应的value push至最终结果中。

class Solution {     public List<List<String>> groupAnagrams(String[] strs) {         Map<String, List<String>> map = new HashMap<>();         for (int i = 0; i < strs.length; i++) {             char[] chars = strs[i].toCharArray();             //对字符串内部进行字符排序             Arrays.sort(chars);             String key = String.valueOf(chars);             //根据key放入不同的组             if (!map.containsKey(key)) {                 //若无法在哈希表中找到key,设置一个空的字符串                 List<String> list = new ArrayList<>();                 list.add(strs[i]);                 map.put(key, list);             } else {                 //在对应的字符串中push结果                 map.get(key).add(strs[i]);             }         }         return new ArrayList<>(map.values());     } } 复制代码

4、LeetCode3无重复字符的最长子串

思路:1.设置一个记录字符数量的字符哈希,char_map;

2.设置一个记录当前满足条件的最长子串变量word;

3.设置两个指针(记作指针i与指针begin)指向字符串第一个字符;

4.设置最长满足条件的子串的长度result;

5.i指针向后逐个扫描字符串中的字符,在这个过程中,使用char_ map记录字符数量。如果word中没出现过该字符:对word尾部添加字符并检查result是否需要更新;否则:begin指针向前移动,更新char_map中的字符数量,直到字符s[i]的数量为1;更新word,将word赋值为begin与i之间的子串。

在整个过程中,使用begin与i维护一个窗口,该窗口中的子串满足题目条件(无重复的字符),窗口线性向前滑动,整体时间复杂度为O(n)。

LeetCode评论代码

class Solution {     public int lengthOfLongestSubstring(String s) {         int result=0; int start=0,end=0;//代表当前窗口的开始和结束位置 Set<Character> set=new HashSet<Character>();         //当窗口中出现重复的字符时,start++,没有重复时,end++,每次更新长度的最大值 while(start<s.length() && end<s.length()){ if(set.contains(s.charAt(end))){ set.remove(s.charAt(start)); start++; } else{ set.add(s.charAt(end)); end++; result=Math.max(result, end-start); } } return result;     } } 复制代码

5、LeetCode189重复的DNA序列

思路:枚举DNA字符串的中所有长度为10的子串,将其插入到哈希Map中,并记录子串数量;遍历哈希map,将所有出现超过1次的子串存储到结果中。算法复杂度O(n)。

LeetCode官方题解

class Solution {   public List<String> findRepeatedDnaSequences(String s) {     int L = 10, n = s.length();     HashSet<String> seen = new HashSet(), output = new HashSet();     for (int start = 0; start < n - L + 1; ++start) {       String tmp = s.substring(start, start + L);       if (seen.contains(tmp)) output.add(tmp);       seen.add(tmp);     }     return new ArrayList<String>(output);   } } 复制代码

6、LeetCode76最小覆盖子串

思路:1.设置两个字符哈希数组,map_ s与map_t, map_s代表当前处理的窗口区间中的字符数量,map_ t代表子串T的字符数量。

2.设置两个指针(记作指针i与指针begin)指向字符串第一个字符;

3.i指针向后逐个扫描字符串中的字符,在这个过程中,循环检查begin指针是否可以向前移动;

如果当前begin指向的字符T中没出现,直接前移begin; 如果begin指向的字符T中出现了, 但是当前区间窗口中的该字符数量足够,向前移动begin,并更新map_ s;否则不能移动begin,跳出检查。

4.指针每向前扫描一个字符, 即检查一下是否可以更新最终结果(找到最小的包含T中各个字符的窗口)。在整个过程中,使用begin与i维护一个窗口,该窗口中的子串满足题目条件(包含T中所有字符),窗口线性向前滑动,整体时间复杂度为O(n)。

LeetCode评论代码

class Solution {     public static String minWindow(String s, String t) {         int left = 0,right = 0;         int count = t.length();         int res_left = 0;         int res_right = -1;         int substringLen = Integer.MAX_VALUE;         int[] map = new int[128];         for (int i = 0; i < t.length(); i++) {             map[t.charAt(i)]++;         }         while (right < s.length()) {             map[s.charAt(right)]--;             if (map[s.charAt(right)] >= 0) {                 count--;             }             while (count == 0) {                 int tempLen = right - left + 1;                 if (substringLen > tempLen) {                     res_left = left;                     res_right = right;                     substringLen = tempLen;                 }                 char departingCharacter = s.charAt(left);                 map[departingCharacter]++;                 if (map[departingCharacter] > 0) {                     count++;                 }                 left++;             }             right++;         }         return s.substring(res_left, res_right + 1);     } }


作者:zust_Isabella
链接:https://juejin.cn/post/7003596346934427655


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐