링크 : https://leetcode.com/problems/find-all-anagrams-in-a-string/
description
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
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".
---
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".
Solution
Code
from collections import Counter
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
N, n = len(s), len(p)
anagrams = dict(Counter(p))
pointer = 0
result = []
while pointer < N :
ch = s[pointer]
if pointer >= n and s[pointer-n] in anagrams :
anagrams[s[pointer-n]] += 1
if ch in anagrams :
anagrams[ch] -= 1
if set(anagrams.values()) == {0} : result.append(pointer-n+1)
pointer += 1
return result
explaination
두 번의 시간초과 끝에 얻은 Aceept
!
시간초과가 난 코드는 O(N^2)으로 substring을 잘라낸 후 substring을 순회하면서 string p와 동일한 문자들로 구성되어 있는지 체크했다. 시간초과가 났다. 🥲
개선한 최종코드는 위와 같다. 로직을 설명하자면, 각 문자의 개수만큼 가지는 anagrams
의 value를 조절하면서 모든 value가 0일 때를 찾는 로직이다. 일단 포인터는 0부터 증가하는데 포인터 인덱스를 가지는 문자를 ch
라 한다. 만약 포인터가 p의 길이보다 크거나 같은 경우에는 빠지는 문자가 생긴다. 포인터에서 n을 뺀 인덱스의 문자가 존재한다면 다시 +1을 해주어야 한다. ch
가 anagrams
에 존재하면 ch
를 키로 가지는 value를 -1해준다. 그리고 집합 자료형을 이용해서 {0}일 때는 모두가 0인 것이므로 결과값에 더해준다!
딕셔너리와 집합 자료형을 이용하여 시간복잡도를 줄인 케이스 😎