코딩 테스트 및 알고리즘/leetcode for google

leetcode hard : K-Similar Strings

띠리링구 2022. 12. 16. 10:12

https://leetcode.com/problems/k-similar-strings/description/

 

K-Similar Strings - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

 

K-Similar Strings

풀기 전

꽤나 막막한거같다. 일단 상수조건에서 문자열의 길이가 꽤나 짧고 포함하는 English letters set 풀도 그렇게 넓지 않은 걸 보니 Backtracking을 살짝 의심할 수도 있을 것 같다.

처음에 보자마자 든 생각은.. 일단 s1과 s2는 anagram이니까 길이는 같을 것이다. 당연히 각 알파벳의 수도 세어보면 둘이 같아야 된다. s1과 s2가 주어졌을 때 일부 글자들은 이미 맞을수도 있다. 예를 들어

s1 = ‘abcdef’

s2 = ‘bacdef’

‘cdef’부분은 이미 맞는다. 그럼 이 맞는 부분은 건들 필요 없는거 아닐까? 꼭 연속적일 필요도 없다.

s1 = ‘abcdef’

s2 = ‘adcbef’

‘acef’부분이 이미 맞는다. 그럼 둘이 다른 부분인 ‘bd’와 ‘db’에 대해서만 re-arrange를 진행하면 되지 않을까 싶은거다.

근데 내가 잘못 생각하는거일까 조금 불안하긴 하다. 다른 부분에 대해서만 리어레인지 한다고 하기엔 상수조건이 너무나 작은거같아서..

일단 예시로 직접 문제를 한번 풀어보자

s1 = ‘abcd’

s2 = ‘dcba’

맞는 게 하나도 없는 경우다.

이 경우 a랑 d를 스왑해주고 b랑 c를 스왑해주면 2번만에 s2랑 똑같이 맞출 수 있다.

하나만 더 풀어보자.

s1 = ‘abcde’

s2 = ‘bcdea’

이번에도 역시 맞는게 하나도 없다.

s2의 맨 앞글자부터 보면서 swap을 진행한다.

‘abcde’ → ‘bacde’

‘bacde’ → ‘bcade’

‘bcade’ → ‘bcdae’

‘bcdae’ → ‘bcdea’

4번만 에 맞췄다.

s2의 앞글자부터 보면서 맞춰나가면 안되는걸까? 사실 그게 정답이라고 하기엔 상수조건이 터무니없이 작긴하다.

코드 설명

(실패)

솔루션 학습

public int kSimilarity(String A, String B) {

        Queue<String> queue = new LinkedList<>();
        Set<String> visited = new HashSet<>();
        queue.offer(A);
        visited.add(A);
        int level = 0;

        while (!queue.isEmpty()) {
            int sz = queue.size();
            for (int i = 0; i < sz; i++) {
                String curNode = queue.poll();
                if (curNode.equals(B)) {
                    return level;
                }
                for (String neighbour : getNeighbours(curNode, B)) {
                    if (!visited.contains(neighbour)) {
                        queue.offer(neighbour);
                        visited.add(neighbour);
                    }
                }
            }
            level++;
        }

        return -1;
    }
    
    private List<String> getNeighbours(String S, String B) { 
        
        List<String> result = new ArrayList<>();
        char[] arr = S.toCharArray(); 
        
        int i = 0;
        for (; i < arr.length; i++) {
            if (arr[i] != B.charAt(i)) {
                break;
            }
        }
                
        for (int j = i + 1; j < arr.length; j++) { 
            if (arr[j] == B.charAt(i)) {
                swap(arr, i, j);             
                result.add(new String(arr));
                swap(arr, i, j);
            }
        }     
        
        return result;
    }
    
    private void swap(char[] arr, int i, int j) {
        
        char tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

string A랑 B가 있을 때 A에서 swap을 한 번 해서 B랑 최소 글자 하나 이상 맞출 수 있는 경우의 수를 모두 나열해놓고 이를 graph의 children으로 취급해서 BFS를 진행한다. 이미 방문한 string은 같은 children을 만들 것이므로 다시 방문하지 않는다.

Time Complexity는 neighbor가 한번 만들어질때 N개에 비례해서 만들어질 수 있어서 Exponential하지 않을까 추측하는데.. 잘은 모르겠다.