<1.10> 가장 짧은 문자거리

mutexlocking·2022년 7월 10일
0

문제
: 영어 소문자로만 구성된 문자열과 , 영어 소문자 한개가 입력되었을 때,
그 문자열을 구성하는 각 문자별로 - 그 문자열 안에서 - 입력된 소문자 까지의 최소 거리를 구하라
(이때 문자열의 길이는 100을 넘지 않는다)

이 문제는 문제만 읽고선 최소 거리를 어떻게 구할 수 있는지 , 요구사항에 따른 - 해결책이 직관적으로 떠오르지 않는 문제였다.

그런 와중에 나는 노트에 예시 문자열을 적어가면서 , 각 문자별로 어떻게 저 최소 거리값이 나오는지 시뮬레이션을 해 보았다.
이때 "teachermode" 안에서 문자 h가 e까지의 최소거리가 어떻게 1이 되는거지, 에 주목했다.

그 해답은 바로 , h 오른쪽에 있는 e 때문에 최소 거리가 1이 되는 것이었다.

그렇다면 최소 거리라고 했으니깐 이 h와 e와의 거리가 더 있다는 의미였고, 잘 살펴보니 문자 h기준 왼쪽 e까지는 거리가 3칸 떨어져 있었다.

이를 통해 아래와 같이 해결책을 마련할 수 있었다.

[해결책]

  • 입력한 문자열을 구성하는 임의의 문자는 모두 자신의 위치 기준으로 왼쪽 방향 또는 오른쪽 방향 중 적어도 한곳에서 , 입력한 소문자를 만날 수 있다.
  • 그말은 즉 문자열을 구성하는 각 문자가 갖는 거리는
    • 자신 기준으로 오른쪽 방향으로 가면서 가장 먼저 특정 문자를 만나는 거리와
    • 자신 기준으로 왼쪽 방향으로 가면서 가장 먼저 특정 문자를 만나는 거리
  • 이렇게 2가지 case밖에 없음을 알게 되었다.
  • 이렇게 2가지 case 밖에 없다면 해결책은 간단했다.

1) 바로 오른쪽 방향으로 이동하면서 만나는 거리를 다 기록하고
2) 왼쪽 방향으로 이동하면서 만나는 거리를 다 기록한 후
3) 이들간의 더 작은 값을 구하면 되는 문제였다

  • 그런데 한가지 중요한 점이, 그 문자열 안에 특정 문자가 반드시 존재하는지의 여부였다.

  • 나는 이 점에 대해서 , 최소한 1개의 문자는 반드시 존재한다고 확신하였는데,
    -> 왜냐하면 그렇지 않았을 경우 [최소거리] 라고 표현할 값을 문제에서 제시하고 있지 않기 때문이다.

  • 이점이 왜 중요한 이유는 최소한 1개의 문자가 존재한다면 임의의 문자 별로,

    • 오른쪽 방향으로 가면서 거리를 기록할 때와
    • 왼쪽 방향으로 가면서 거리를 기록할 때
  • 두 case 중 반드시 한 case에서 만난다는 사실이 보장되기 때문이다

  • 이 사실만 보장된다면 , 두 방향 중 각 방향으로 탐색을 하면서

    • 한쪽 방향에서 만나지 못해 , 문제 조건상 나올 수 없는 거리 100을 기록해두어도 (문자열 길이는 100을 넘지 않는다)
    • 다른쪽 방향에서 반드시 만나 100보다 작은 거리값이 기록됨이 보장되면
    • 두 방향의 거리를 가지고 최소 거리를 구할 때 유효한 최소거리가 반드시 나오기 때문이다.

위와 같은 사고의 흐름으로, 어떻게 최소거리가 구해지는지 시뮬레이션 해보고,
이 때 놓치지 않는 조건은 없는지 생각해 봄으로써
오른쪽/왼쪽 각 방향으로 탐색한 거리를 기록 후 - 이들을 가지고 최소거리를 구하자
라는 해결책을 고안해 낼 수 있었다.

이에 대한 코드 구현은 아래와 같다.

import java.util.Arrays;
import java.util.Scanner;


public class Main {

    /**
     * 이 문제의 중요한 가정 : 반드시 입력한 문자 c는 문자열 안에 있다!
     * 만약 그렇지 않으면 , 최소 거리를 어떻게 표시할 지 문제에 주어져 있지x
     * -> 이렇게 최소 한개의 문자 c가 문자열 안에 있다면 , 오른쪽으로 이동하면서 거리를 찾든 or 왼쪽으로 이동하면서 거리를 찾든 ,
     * 둘 중 한 방향에서는 만나게 되어 있음 !! -> 이를 전제로 해결하기 때문에 , 100을 넣어도 됨!!
     * */
    public static int[] solution(String str, char c){

        int[] minDistance = new int[str.length()];
        int[] distanceFromRight = new int[str.length()];
        int[] distanceFromLeft = new int[str.length()];
        int distance = 0;
        int idx = 0;

        //0. 문자열을 char 배열로 변환
        char[] charArr = str.toCharArray();

        //1. for문과 내부 while문을 돌면서 - 오른쪽 c하고 떨어진 거리를 계산
        for(int i=0; i<str.length(); i++){

            idx = i;

            // 오른쪽으로  이동하면서 문자 c가 있는지 살펴보되 , 오른쪽 끝까지 가도 업으면 절대 나오지 않을 큰 값 100을 대입
            while(idx < str.length()){
                if(charArr[idx] == c){
                    distanceFromRight[i] = distance;
                    distance = 0;
                    break;
                } else{
                    distance++;
                    idx++;
                }
            }

            if(idx >= str.length()){
                distanceFromRight[i] = 100;
                distance = 0;
            }
        }

        //2. for문과 내부 while문을 돌면서 - 왼쪽 e하고 떨어진 거리를 계산
        for(int i=0; i<str.length(); i++){

            idx = i;

            // 왼쪽으로  이동하면서 문자 c가 있는지 살펴보되 , 오른쪽 끝까지 가도 업으면 절대 나오지 않을 큰 값 100을 대입
            while(idx >= 0){
                if(charArr[idx] == c){
                    distanceFromLeft[i] = distance;
                    distance = 0;
                    break;
                } else{
                    distance++;
                    idx--;
                }
            }

            if(idx < 0){
                distanceFromLeft[i] = 100;
                distance = 0;
            }
        }

        //3. 위 1,2 결과 배을 값을 가지고 , 각 element중 작은값으로만 이루어진 최소 거리를 배열에 담아서 리턴
        for(int i=0; i<str.length(); i++){
            minDistance[i] = (distanceFromRight[i] < distanceFromLeft[i]) ? distanceFromRight[i] : distanceFromLeft[i];
        }

        return minDistance;

    }

    public static void main(String[] args) {

        //0. Scanner 준비
        Scanner sc = new Scanner(System.in);

        //1. 문자열 과 문자를 입력받음 (공백을 구분자로 하여)
        String str = sc.next();
        char c = sc.next().charAt(0);

        //2. 입력받은 문자열과 문자를 인자로 넘겨 solution()을 호출후 -> 결과 배열을 반환받음
        int[] result = solution(str, c);

        //3. 결과 배열 출력
        Arrays.stream(result)
                .forEach(i -> System.out.print(i + " "));
    }
}

사실 이 문제의 해결책을 어느정도 생각한 후, 스택으로 코드 구현을 시도했다가 실패했었는데,
너무 어렵게 접근하기 보다는 - 출제자의 의도 / 문제에서 물어보고자 하는 점을 잘 파악안 후 , 이를 코드로 구현하는 것이 중요한 것 같다고 느꼈다.

[정리할 내용]

  • sc.next().charAt(0)
    : 문자 콘솔 입력방법을 몰라 이렇게 입력받았었는데,
    강의를 보고 이렇게 입력받는게 맞다는걸 확실히 알게 되었다!
profile
개발자가 되고자 try 하는중

0개의 댓글