Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 코딩테스트
- 오블완
- 인접 행렬
- 개발자루틴
- 코딩테스트준비
- 자료구조
- #코드트리 #코딩테스트 #코테공부 #백트래킹 #알고리즘 기초
- 데이터베이스
- 프로그래밍 언어
- 티스토리챌린지
- 프로그래머스
- 자바스크립트
- 웹
- 1일1코테
- C
- 갭체크
- 파이썬
- 개발자취업
- 운영체제
- 코딩테스트사이트추천
- 99클럽
- 코테공부
- til
- Java
- 연결 리스트
- 항해99
- 코드트리
- 자바
- 알고리즘
- 플로이드-워셜
Archives
- Today
- Total
와드의 블로그
튜플 본문
문제
특정 튜플을 표현하는 집합이 담긴 문자열 s가 주어질 때, s가 표현하는 튜플을 배열에 담아 반환하는 프로그램을 작성하는 문제입니다. 예를 들어, 튜플이 (2, 1, 3, 4)인 경우, 이는 집합 {{2}, {2, 1}, {2, 1, 3}, {2, 1, 3, 4}}로 표현될 수 있으며, 집합의 순서는 바뀔 수 있습니다.
- 입력: 튜플의 집합을 나타내는 문자열 s (길이 5 이상 1,000,000 이하, 원소는 100,000 이하의 자연수)
- 출력: 원본 튜플을 나타내는 정수 배열
링크: https://school.programmers.co.kr/learn/courses/30/lessons/64065
풀이 1: 문자열 파싱 (수동 추출)과 길이를 기준으로 한 정렬
문자열에 포함된 괄호를 하나씩 해석하여 각 부분 집합을 분리하고, 원소가 적은 부분 집합부터 순차적으로 탐색하여 새롭게 추가되는 원소를 찾아내는 방식입니다.
- 문자열 파싱 (수동 추출): 입력된 문자열 s에서 가장 바깥쪽 괄호를 제외한 1부터 s.length() - 1까지 순회합니다.
- 열린 괄호 {를 만나면 flag를 true로 설정하여 원소 기록을 시작합니다.
- 닫힌 괄호 }를 만나면 지금까지 StringBuilder에 기록된 숫자 문자열을 리스트(list)에 추가하고, StringBuilder를 비운 뒤(setLength(0)) flag를 false로 돌립니다.
- flag가 true인 상태에서는 콤마(,)와 숫자를 모두 StringBuilder에 덧붙여 부분 집합의 형태를 만들어냅니다.
- 길이 기준 오름차순 정렬: 분리된 부분 집합 문자열들을 담은 리스트를 '문자열의 길이' 기준으로 오름차순 정렬합니다. 가장 짧은 문자열이 튜플의 첫 번째 원소이고, 길이가 길어질수록 새로운 원소가 하나씩 추가되는 구조이기 때문입니다.
- 새로운 원소 추출 및 직접 할당 최적화:
- 가장 짧은 부분 집합부터 순회하며 콤마(,)를 기준으로 숫자를 분리합니다.
- 빠른 중복 검사를 위해 크기가 100,001인 boolean 배열(check)을 사용합니다.
- 튜플의 최종 길이는 부분 집합의 개수(list.size())와 동일합니다. 따라서 정답 배열 ans를 이 크기만큼 미리 선언해 두고, 중복되지 않은 새로운 숫자를 발견하면 별도의 리스트를 거칠 필요 없이 현재 인덱스 i에 직접 ans[i] = x 형태로 삽입하여 메모리와 변환 시간을 단축합니다.
코드 1
import java.util.*;
class Solution {
public int[] solution(String s) {
List<String> list = new ArrayList<>();
StringBuilder sb = new StringBuilder();
boolean flag = false;
// 1. 바깥 괄호를 제외하고 순회하며 부분 집합 문자열 파싱
for (int i = 1; i < s.length() - 1; i++) {
char c = s.charAt(i);
if (c == '{') {
flag = true;
} else if (c == '}') {
list.add(sb.toString());
sb.setLength(0);
flag = false;
} else if (flag) {
sb.append(c);
}
}
// 2. 부분 집합 문자열을 길이를 기준으로 오름차순 정렬
Collections.sort(list, (s1, s2) -> {
return s1.length() - s2.length();
});
int[] ans = new int[list.size()];
boolean[] check = new boolean[100001];
// 길이가 짧은 부분 집합부터 순회하며 새로운 원소 발굴
for (int i = 0; i < list.size(); i++) {
String[] tmp = list.get(i).split(",");
for (String a : tmp) {
int x = Integer.parseInt(a);
// 이미 튜플에 들어간 원소라면 건너뜀
if (check[x]) continue;
check[x] = true;
ans[i] = x;
}
}
return ans;
}
}
풀이 2: split과 HashSet을 활용한 풀이
문자열을 한 글자씩 순회하는 대신 자바의 내장 문자열 자르기 함수(split)와 정규식을 활용하여 코드를 단축시킨 풀이입니다.
- 정규식을 활용한 단괄 파싱: 가장 바깥쪽의 괄호 {{ 와 }} 를 substring으로 잘라냅니다. (s.substring(2, s.length() - 2)) 그 후 내부의 집합들을 구분하는 },{ 를 기준으로 문자열을 split 합니다. 자바 정규식에서 괄호 기호는 특수문자이므로 \\} 와 같이 이스케이프 처리가 필요합니다.
- 배열 정렬: 분리된 문자열 배열을 길이를 기준으로 오름차순 정렬합니다.
- HashSet의 add 특성 활용: HashSet의 add 메서드는 값이 집합에 새롭게 추가되었을 때만 true를 반환하고, 이미 존재한다면 false를 반환합니다. 이를 if문의 조건으로 활용하면 중복 검사와 튜플 배열 생성을 동시에 아주 깔끔하게 처리할 수 있습니다.
코드 2
import java.util.*;
class Solution {
public int[] solution(String s) {
// 1. 가장 바깥쪽 괄호 '{{' 와 '}}' 를 제거하고 "},{" 를 기준으로 문자열 분리
String[] arr = s.substring(2, s.length() - 2).split("\\},\\{");
// 2. 문자열 길이를 기준으로 오름차순 정렬
Arrays.sort(arr, (a, b) -> a.length() - b.length());
int[] ans = new int[arr.length];
int idx = 0;
Set<String> set = new HashSet<>();
// 3. 길이가 짧은 문자열부터 탐색하며 새로운 숫자 발굴
for (String str : arr) {
String[] numbers = str.split(",");
for (String val : numbers) {
// set.add()는 기존에 없던 새로운 원소가 추가될 때만 true를 반환
if (set.add(val)) {
ans[idx++] = Integer.parseInt(val);
}
}
}
return ans;
}
}
알고리즘 분류
문자열 (String), 파싱 (Parsing), 정렬 (Sorting), 해시를 사용한 집합 (Hash Set)
'PS > 프로그래머스' 카테고리의 다른 글
| 연속된 부분 수열의 합 (0) | 2026.04.21 |
|---|---|
| 2개 이하로 다른 비트 (1) | 2026.04.20 |
| 호텔 대실 (0) | 2026.04.18 |
| 두 큐 합 같게 만들기 (0) | 2026.04.17 |
| 숫자 카드 나누기 (1) | 2026.04.05 |