438. Find All Anagrams in a String

LJM·2022년 12월 16일
0

LeetCode

목록 보기
4/10

Given two strings s and p, return an array of all the start indices of p's anagrams in s. You may return the answer in any order.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

anagram 이란 글자의 배치순서만 다른것이다 abc 의 anagram 은 acb,bac,bca,cab,cba 등이 있다
s 스트링에서 p의 anagram 찾고 첫번째 인덱스를 반환하는 문제이다

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".

c++ 로 8월에 이미 풀었던 문제임에도 불구하고 푸는데 3시간이나 걸렸다...
java로 풀어보았다

해시맵과 슬라이딩윈도우(알고리즘?)을 사용하였다

public List<Integer> findAnagrams(String s, String p) 
{
        List<Integer> ret = new ArrayList<Integer>();

        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
      
        for(int i = 0; i < p.length(); ++i)
        {
            if(map.get(p.charAt(i)) == null)
                map.put(p.charAt(i), 1);
            else
                map.put(p.charAt(i), map.get(p.charAt(i)) + 1);
        }

        int left = 0;
        int right = 0;
 
        while(right < s.length())
        {
            if(map.get(s.charAt(right)) != null)
            {
                map.put(s.charAt(right), map.get(s.charAt(right)) - 1);
            }

            right++;

            if((right - left) > p.length())
            {
                if(map.get(s.charAt(left)) != null)
                {
                    map.put(s.charAt(left), map.get(s.charAt(left)) + 1);
                }
                left++;
            }

            boolean isAllZero = true;
            for (Map.Entry<Character, Integer> set : map.entrySet()) 
            {
                if( 0 != set.getValue())
                {
                    isAllZero = false;
                    break;
                }                
            }
                
            if(isAllZero==true)
            {
                ret.add(left);
            }
        }

        return ret;
    }

코드가 너무 길다.. 비효율적인 부분을 줄이는게 항상 어렵다.. 예를들어 해시맵에서 글자마다 숫자를 카운트 하고 매번 전부 0인지 확인하는 것보다 더 좋은 방법이 있지않을까 생각해본다.

예전에 c++로 풀었던 기록이 남아있네! 릿코드에서 submit 하면 코드 기록을 저장하는것 같다

vector<int> findAnagrams(string s, string p) 
  {

        vector<int> ret;
        
        map<char,int> hashmap;
        
        map<char,int>::iterator iter;

        for(int i = 0; i < p.length(); ++i)
        {
            iter = hashmap.find(p[i]);
            if(iter != hashmap.end())
                iter->second += 1;
            else
                hashmap.insert(make_pair(p[i], 1));
        }
        
        int begin = 0;
        int end = begin + p.length() -1;

        int hashsize = hashmap.size();
        
         for(int i = 0; i < p.length(); ++i)
         {         
             iter = hashmap.find(s[i]);
             if(iter != hashmap.end())
             {
                 iter->second -= 1;
                 if(iter->second ==0 )
                    hashsize--; 
             }
                 
         
             if(0 == hashsize)
                 ret.push_back(begin);
         }
        
        ++begin;
        ++end;

        
        while(end < s.length())
        {   
            iter = hashmap.find(s[begin-1]);
            if(iter != hashmap.end())
            {            
                iter->second += 1;
                if(iter->second == 1)
                    hashsize++;
            }
           
            iter = hashmap.find(s[end]);
            if(iter != hashmap.end())
            {
                iter->second -= 1;
                if(iter->second == 0)
                    hashsize--;
            }
        
            
            if(0 == hashsize)
                ret.push_back(begin);
            
            ++begin;
            ++end;
        }         
            
        

     
        return ret;
                   
    }

차이점은 hashsize 변수를 추가하고 각각 글자의 개수가 0이면 -하고 글자가 1되면 + 카운트를 하는것이다. 그러면 전체 순회하면서 전부 0인지 체크하는 코드가 필요없게 된다

public List<Integer> findAnagrams(String s, String p) {
        List<Integer> ret = new ArrayList<Integer>();

        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
      
        int hashcount = 0;
        for(int i = 0; i < p.length(); ++i)
        {
            if(map.get(p.charAt(i)) == null)
            {
                map.put(p.charAt(i), 1);
                hashcount++;
            }             
            else
            {
                map.put(p.charAt(i), map.get(p.charAt(i)) + 1);
            }
                
        }

        int left = 0;
        int right = 0;

        while(right < s.length())
        {
            if(map.get(s.charAt(right)) != null)
            {
                map.put(s.charAt(right), map.get(s.charAt(right)) - 1);
                if(map.get(s.charAt(right)) == 0)
                    hashcount--;
            }

            if((right - left) > p.length()-1)
            {
                if(map.get(s.charAt(left)) != null)
                {
                    map.put(s.charAt(left), map.get(s.charAt(left)) + 1);
                    if(map.get(s.charAt(left)) == 1)
                        hashcount++;
                }
                left++;
            }

            right++;

            if(hashcount == 0)
            {
                ret.add(left);
            }
        }

        return ret;
    }

코드를 개선했지만 속도는 그닥 차이가 나지 않는다

profile
게임개발자 백엔드개발자

0개의 댓글