[leetcode] Valid Anagram Find All Anagrams in a String
Posted Lin.B
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[leetcode] Valid Anagram Find All Anagrams in a String相关的知识,希望对你有一定的参考价值。
Valid Anagram
Given two strings s and t , write a function to determine if t is an anagram of s.
Example 1:
Input: s = "anagram", t = "nagaram" Output: true
Example 2:
Input: s = "rat", t = "car" Output: false
Note:
You may assume the string contains only lowercase alphabets.
Follow up:
What if the inputs contain unicode characters? How would you adapt your solution to such case?
分析:题目要求判断两个字符串s和t是否是颠倒字母顺序构成的,比较简单,就是字符串t是否是s中的字符组成。这个题目看了一下有两个思路,一个直接对字符串排序,然后如果相等就是true,不等就是false;第二个思路就是用HashMap来做。因为比较简单,思路也比较清晰,就讨巧用python 一句话解决一下吧
1 class Solution(object): 2 def isAnagram(self, s, t): 3 """ 4 :type s: str 5 :type t: str 6 :rtype: bool 7 """ 8 return sorted(s) == sorted(t)
Find All Anagrams in a String
Given a string s and a non-empty string p, find all the start indices of p‘s anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.
The order of output does not matter.
Example 1:
Input: s: "cbaebabacd" p: "abc" Output: [0, 6] Explanation: The substring with start index = 0 is "cba", which is an anagram of "abc". The substring with start index = 6 is "bac", which is an anagram of "abc".
Example 2:
Input: s: "abab" p: "ab" Output: [0, 1, 2] Explanation: The substring with start index = 0 is "ab", which is an anagram of "ab". The substring with start index = 1 is "ba", which is an anagram of "ab". The substring with start index = 2 is "ab", which is an anagram of "ab".
分析:这个题目要求再s中找t的字串位置(t可以是颠倒顺序的)。其实思路很简单,一个for循环过去进行对比就行了,关键就是在于如何确定两个字符串是否是颠倒的。刚开始我想的是用异或来做,可是代码写好之后发现有问题,比如s某个字串中有"aa",但是p中有"bb",那么用异或做的话就认为是相同的了,所以不能用异或做。白浪费了半个小时去找错,无语。。。
方法1:想到用一个list来保存p中的字符,然后去找s中的字串,如果s中某个字符再list中,就从list中删掉这个字符,最后如果list为空的话,就说明两个字符串是由相同的字符构成的了。代码如下:
1 public List<Integer> findAnagrams(String s, String p) { 2 List<Integer> res = new ArrayList<>(); 3 List<Character> list = new ArrayList<>(); 4 for ( char c : p.toCharArray() ) list.add(c); 5 for ( int i = 0 ; i <= s.length() - p.length() ; i ++ ){ 6 List<Character> list_t = new ArrayList<>(list); 7 boolean flag = true; 8 for ( int j = i ; j < i + p.length() ; j ++ ){ 9 if ( !list_t.contains(s.charAt(j)) ){ 10 flag = false; 11 break; 12 } 13 list_t.remove((Object)s.charAt(j)); 14 } 15 if ( flag && list_t.isEmpty() ) res.add(i); 16 } 17 return res; 18 }
结果跑到第34个用例就超时了,这说明设计题目的人可能就不想让我们借助一些简单的思路来做,还是得重新找最本质的解法。
方法2:窗口滑动法。做字符串匹配问题时,窗口滑动是非常适用的方法,因为它省去了很多重复的比较。窗口滑动的核心还是两个指针left、right。
定义:结果:一个窗口内的字符恰好包含p中所有的字符,叫做一个结果。
第一步,将map初始化,形成一个p中字符与出现次数对应的map。
第二步,扩展窗口容量。然后初始化left和right为0,形成一个大小为0的窗口,然后右边界right不断向又探查,如果right位置的字符在map中,就令对应的value减1,该过程直到窗口中包含一个完整的结果为止,可以用一个counter变量来标识,counter初始值为map.size(),然后遇到一次p中的字符就减1,注意对于每个字符counter只减一次,然后当counter==0的时候,进入下一个步骤。
第三步,我们要做的工作是对left进行动作,缩减窗口容量。当窗口包含一个结果以后,为了进一步遍历,我们需要缩小窗口使窗口不再包含全部的p,同样,如果map[char]>=0,表明一个在p中的字符就要移除窗口,那么count ++,以此类推。 然后通过窗口长度判断是否是正确答案。
可以说滑动窗口这种思想,关键点在于:
- map中存储值的意义
- 窗口什么时候扩展和收缩,对应于left和right值什么时候发生变化。
在解题的时候,首先尝试扩展窗口right,看看什么时候包含了一个结果,记录结果。然后缩小左边界left,直到窗口不在包含一个可能解!接着就可以继续扩展窗口了,以此类推。
本题代码如下:
1 public List<Integer> findAnagrams(String s, String p) { 2 List<Integer> res = new ArrayList<>(); 3 Map<Character, Integer> map = new HashMap<>(); 4 for (char c : p.toCharArray()) map.put(c, map.getOrDefault(c, 0) + 1); 5 6 int counter = map.size(); //代表窗口内是否包含p中全部的字符 7 int left = 0; //代表窗口的左边界 8 int right = 0; //代表窗口的右边界 9 10 while (right < s.length()) { 11 char c = s.charAt(right); 12 13 //下面这个代码段表示窗口右边界的扩展过程,扩展到left——right中包含p中全部的字符为止。 14 if (map.containsKey(c)) { 15 map.put(c, map.get(c) - 1); 16 if (map.get(c) == 0) counter--; //表示p中的字符再窗口内出现一次 17 } 18 right++; 19 20 //下面的代码查找窗口是否满足要求,缩小窗口直到窗口不包含一个可能的解 21 while (counter == 0) { //counter==0的时候就是窗口内包含了p的全部字符 22 char left_c = s.charAt(left); 23 if (map.containsKey(left_c)) { 24 map.put(left_c, map.get(left_c) + 1); 25 if (map.get(left_c) > 0) counter++; // 让右边界继续增大,寻找新的窗口 26 } 27 if (right - left == p.length()) res.add(left); 28 left++; 29 } 30 } 31 return res; 32 }
在解决诸如substring这类问题时,不妨尝试想一想滑动窗口。
leetcode上还有一些题目都可以用类似的方法来求解。先mark一下,明天再处理这些问题。
https://leetcode.com/problems/minimum-window-substring/
https://leetcode.com/problems/longest-substring-without-repeating-characters/
https://leetcode.com/problems/substring-with-concatenation-of-all-words/
https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/
https://leetcode.com/problems/find-all-anagrams-in-a-string/
以上是关于[leetcode] Valid Anagram Find All Anagrams in a String的主要内容,如果未能解决你的问题,请参考以下文章