알고리즘 및 자료구조

문자열(String)을 이용한 문제 풀이 (3문제)

지팡구 2022. 12. 1. 15:51
본 내용은 인프런 자바(Java) 알고리즘 문제풀이 : 입문 - 코딩테스트 대비 강의 문제를 기반으로 포스팅 한 내용입니다.

문제
  • 문자거리
  • 문자열 압축
  • 암호(replace(), parseInt(string, 2))

문제 1. 문자거리

문제 설명과 예시, 그리고 내가 접근하고자 했던 방식
한 개의 문자열 s와 문자 t가 주어지면 문자열 s의 각 문자가 문자 t와 떨어진 최소거리를 출력하는 프로그램을 작성

ex) teachermode e -> 1 0 1 2 1 0 1 2 2 1 0

     <접근방식> 고민해보기 정방향 -> 역방향 순으로 반복문을 통해 해당 요소가 있는지 확인하고, 값을 기준으로 최소거리를 저장하면 됐었음.
     본 강의에서는 Math.min()을 이용해 기존에 있던 배열의 요소와 새로운 값을 비교해 더 작은 값을 넣는 방식 (더 간단함)
     나는 이 부분을 직접 조건식을 통해 해결하려고 했었음
코드
 public int[] solution(String s,char t){
 	int p = 1000;
	int[] answer= new int[s.length()];
 	for(int i=0; i<s.length(); i++){
        if(s.charAt(i)==t){
            p=0;
            answer[i]=p;
        }else
        	p++;
 			answer[i]=p;
     }
 	p=1000;
 for(int i=s.length()-1; i>=0; i--){
 	if(s.charAt(i)==t)p=0;
 		else{
 			p++;
 			answer[i]=Math.min(answer[i],p);
      }
 	}
 	return answer;
 }

1. 파라미터로 전달받은 문자열(s)와 문자(t)를 이용한다.

2. 첫번째 반복문은 정방향, 두 번째 반복문은 역방향

 

반복문이 정방향 역뱡향이 있는 이유는, 전달받은 문자열에 중복된 문자가 있을 수 있는데, 문자의 위치에 따라 최소거리가 달라질 수 있기때문에 그것을 검출하기 위함


문제 2. 문자열 압축

문제 설명과 예시, 그리고 내가 접근하고자 했던 방식
 설명 : 알파벳 대문자로 이루어진 문자열을 입력받아 -> 같은 문자가 연속으로 반복되는 경우 반복 문자 바로 오른쪽에 반복 횟수를 표기

ex) KKHSSSSSSSF -> K2H1S7F1 이런방식으로 -> 이렇게 하는 줄 알았는데, 1개인 부분은 1은 안찍고 그냥 알파벳만 찍음
 
 고민해보기
 우선 반복문 탐색(String 길이) -> 문자열 앞, 뒤 요소 비교하고 같으면 count 증가, 다르면 해당 문자열 요소와 count 저장
 근데 이렇게 하면 StringboundaryException 발생 -> 당연함 요소가 없는데 어떻게 비교하냐? (이 부분에서 고민 많이 함)

이 부분에서 고민이 많아졌다. 그 이유는 인덱스 요소를 비교하는데, 마지막 요소를 비교할 수 있는 방법이 없었다.

해결책 : 그냥 문자열에 빈 여백을 하나 추가...

 

코드
public String solution(String a) {
    String s = a + " ";
    String answer = "";
    int count = 1;
    for (int i = 0; i < s.length() - 1; i++) {
        if (s.charAt(i) == s.charAt(i + 1)) {
            count++;
        } else {
            answer = answer + s.charAt(i);
            if (count > 1) {
                answer = answer + Integer.toString(count);
                count = 1;
            }
        }
    }
    return answer;

1. 입력된 문자열에 빈 여백 하나 더해주기.

2. 여기서 count는 문자열에 해당 문자가 몇 개 있는지 check 하기 위해서 선언

3. 해당 인덱스와 다음 인덱스를 이용해 앞, 뒤 문자를 확인하고 같으면 cnt ++ 

    다르면 비교중인 해당 인덱스를 answer에 추가하고, cnt가 1보다 크면 anwer 뒤에 저장(형변환까지), 그리고 cnt 1 초기


문제 3. 암호(replace(), parseInt(string, 2))

문제 설명과 예시, 그리고 내가 접근하고자 했던 방식
 설명 : 알파벳 한 문자마다 # or *이 7개로 구성되어 있다 -> 입력된 # or * 일곱자리의 이진수(#->1, *->0)으로 변환 ->
 이렇게 바뀐 이진수를 다시 10진수로 변환  -> 이 10진수를 아스키 코드로 변환 -> 그리고 출력

ex) 4 #****###**#####**#####**##**  -> COOL

로직 순서 -> 입력받은 문자열을 이진수로 변환 -> 이 이진수를 쪼갬과 동시에 10진수로 변환하고, 그 요소를 배열에 저장
 -> 배열의 인덱스엔 10진수가 저장되어있으니까 이 배열을 순회하면서 10진수를 아스키코드로 변환 -> 출력 끝!

고민해보기 <접근방식>
 로직을 위의 설명처럼 구성했음. 과연 더욱 효율적인 방법이 있을까?

 

코드

위의 로직 순서대로 코드를 직접 작성하니 뭔가 코드가 엄청 길어지고 성능도 별로였다.

public void solution(int num, String p){
    String a = "";
    String answer = "";
    int []arr = new int[num];
    for(int i=0; i<p.length(); i++){
        if(p.charAt(i)=='#'){
            a=a+'1';
        }else{
            a=a+'0';
        }
    }
    for(int i=0; i<num; i++){
        String b=a.substring(i*7,((i*7)+7));
        int c = Integer.parseInt(b,2);
        arr[i]=c;
    }
    for(int i=0; i<num; i++){
        char ch = (char) arr[i];
        System.out.print(ch);
    }

내가 구현한 코드는 윗 코드와 같다.

1. 첫 번째 반복문에서 전달받은 문자열을 이진수로 바꿔줄 것.

2. 다음 반복문에선 요소를 7개씩 자르고, 자른 요소를 10진수로 변환 후  배열에 저장

3. 마지막 반복문은 저장된 배열속 요소를  아스키 코드로 형변환

 

코드를 구현하고 해설강의를 보았는데, 해설강의의 코드는 다음과 같았다.

public String solution(int n, String s){
    String answer="";
    for(int i=0; i<n; i++){
        String tmp=s.substring(0,7).replace('#','1').replace('*','0');
        int num = Integer.parseInt(tmp,2);
        answer += (char)num;
        s=s.substring(7);
    }
    return answer;
}

너무 간결했다...

 

오늘 문자열 챕터의 마지막 3문제를 정복하며 어떻게 코드를 더욱 간결하게 짤 수있을까?

어떻게 로직에 접근할 수 있을가? 

이 부분에는 어떻게 무엇을 사용하는게 좋을까? 라는 여러가지 생각을 하면서 직접 펜과 종이를 이용해 문제를 해결하는 시간을 가졌다.