알고리즘/프로그래머스 카카오
알고리즘) 카카오 블라인드 채용 2020, 문자열 압축
Zin0_0
2020. 5. 1. 15:53
반응형
Kakao Blind Recruitment 2020
문자열 압축
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
문자열은 제일 앞부터 정해진 길이만큼 잘라야 합니다.
따라서 주어진 문자열을 x / ababcdcd / ababcdcd 로 자르는 것은 불가능 합니다.
이 경우 어떻게 문자열을 잘라도 압축되지 않으므로 가장 짧은 길이는 17이 됩니다.
풀이
(2020.05.01)
문자열을 제일 앞부터 정해진 길이만큼 자르는게 중요해서 저 조건만 따로 적어봤다. 처음 문자열 부터 자르는 것과 중복되는 문자열의 갯수를 파악하는 것에 주의한다면 어려운 문제는 아니었다.
1. 자를 문자열의 길이만큼 loop를 돌렸다. (1~전체 문자열 길이의 절반, 편의상 n이라 칭하겠다)
2. 첫번째 Index부터 n만큼 자른 문자열을 저장해놓고, n~2n까지 문자열을 잘라 같은지 비교한다.
3. 같다면 카운트를 증가시켜 몇개의 자른 문자열이 중복되는지 저장한다.
4. 이 전 글자와 같지 않다면 중복된 문자열 길이를 변환하여, 줄어든 글자 수 만큼 전체 문자열 길이에서 빼준다.
5. 마지막까지 문자열 중복이 이어진 경우를 위해, 검사 후 줄어든 글자 수 만큼 전체 길이에서 빼준다.
(2020.06.05)
첫번째로 푼 방식과 비슷하게 풀었다. 전체 문자열 길이/2 ~ 1 까지 문자열을 제일 앞부터 탐색해서 카운트를 세주면서 글자를 줄여나갔을 때, 최소값이 되는 값을 저장했다. 저번 풀이에서는 String.ValueOf로 길이를 구했다면, 이번에는 반복문을 통해 10^n승보다 작은 값에대해 찾아주어 길이를 구해줬다. 또 차이점이 있다면, times를 사용하지 않았다는 것 정도가 되겠다.
코드 1
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Problem1_2019 {
static int reduceLen(int cnt, int div) { // 글자 줄어든 만큼 반환
return div*cnt - (String.valueOf(cnt).length() + div); // 원래 길이 - 바뀐 길이
}
static int solution(String s) {
int len = s.length(); // 전체 길이
int answer;
int min = 1001; // 1~1000자리의 문자열이기 때문에 최솟값은 최대보다 1 큰 1001로 설정
int cnt=1; // 중복된 횟수 카운팅
if(len <=2) {
return len;
}
for(int div =len/2; div >0; div--) { // 문자열 자를 길이만큼 절반 ~ 1까지
answer = len; // 답 초기화
String tmp = s.substring(0, div); // 첫번째 인덱스부터 길이만큼 자르기
for (int times = 1; times <= len / div; times++) { // 100잔데 2개로 자르면 50개를 비교해야하기 때문.
if(div*(times+1) > len) { // 최대 글자 넘어가는 경우는 check 안함
break;
}
String dest = s.substring(div * times, div + div * times); // next 문자열
if (tmp.equals(dest)) { // 전에랑 글자 같아?
cnt++; // 횟수 증가
} else { // 여러번 중복되는 것 체크
if (cnt != 1) { // 현재까지 중복된 갯수만큼 글자 줄여주기
answer -= reduceLen(cnt,div); // 줄어든 글자 수 만큼 빼주기
cnt = 1; // 중복 체크 횟수 초기화
}
}
tmp = dest; // 비교 글자 바꾸기
}
if (cnt != 1) { // 검사 끝나고 잔여 횟수가 남아있으면
answer -= reduceLen(cnt,div); // 줄어든 글자 수 만큼 빼주기
}
min = min > answer ? answer : min;
cnt = 1;
}
answer = min;
return answer;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inStr = br.readLine();
System.out.println(solution(inStr));
br.close();
}
}
코드 2
class Solution {
public int solution(String s) {
int len = s.length();
int answer = len;
if(answer >2) { // 길이 2 이하는 의미가 없음
for(int letters=len/2; letters>0; letters--) {
int cnt =1;
int convertLen = len;
String prev = s.substring(0,letters);
for(int i=letters; i<=len-letters; i+=letters) { // 시작점
String now = s.substring(i,i+letters);
if(now.equals(prev)) { // 같은 경우
cnt++;
} else { // 다른 경우
if(cnt !=1) { // 줄여줘야함
convertLen -= reduceNum(cnt,letters);
cnt=1;
}
}
prev = now;
}
if(cnt !=1) {
convertLen -= reduceNum(cnt,letters);
}
answer = Math.min(convertLen,answer);
}
}
return answer;
}
private int reduceNum(int cnt, int len) {
int result = len*cnt;
for(int i=1; i<=5; i++) { // 숫자 길이
if(cnt < (int)Math.pow(10,i)) {
cnt = i;
break;
}
}
len += cnt;
return result-len;
}
}
반응형