Problem
Implement a simple text editor. The editor initially contains an empty string, S. Perform Q operations of the following 4 types:
- append(W) - Append string W to the end of S.
- delete(k) - Delete the last k characters of S.
- print(k) - Print the k^th character of S.
- undo - Undo the last (not previously undone) operation of type 1 or 2, reverting S to the state it was in prior to that operation.
Example
S = 'abcde'
ops = ['1 fg', '3 6', '2 5', '4', '3 7', '4', '3 4']
operation
index S ops[index] explanation
----- ------ ---------- -----------
0 abcde 1 fg append fg
1 abcdefg 3 6 print the 6th letter - f
2 abcdefg 2 5 delete the last 5 letters
3 ab 4 undo the last operation, index 2
4 abcdefg 3 7 print the 7th characgter - g
5 abcdefg 4 undo the last operation, index 0
6 abcde 3 4 print the 4th character - d
The results should be printed as:
f
g
d
Input Format
The first line contains an integer, Q, denoting the number of operations.
Each line i of the Q subsequent lines (where 0 ≤ i ≤ Q) defines an operation to be performed. Each operation starts with a single integer, t (where t ∈ {1, 2, 3, 4}), denoting a type of operation as defined in the Problem Statement above. If the operation requires an argument, t is followed by its space-separated argument. For example, if t = 1 and W = "abcd", line i will be 1 abcd.
Constraints
- 1 ≤ Q ≤ 10^6
- 1 ≤ k ≤ |S|
- The sum of the lengths of all W in the input ≤ 10^6.
- The sum of k over all delete operations ≤ 2*10^6.
- All input characters are lowercase English letters.
- It is guaranteed that the sequence of operations given as input is possible to perform.
Output Format
Each operation of type 3 must print the k^th character on a new line.
Sample Input
STDIN Function
----- --------
8 Q = 8
1 abc ops[0] = '1 abc'
3 3 ops[1] = '3 3'
2 3 ...
1 xy
3 2
4
4
3 1
Sample Output
c
y
a
Explanation
Initially, S is empty. The following sequence of 8 operations are described below:
- S = "". We append abc to S, so S = "abc".
- Print the 3rd character on a new line. Currently, the 3rd character is c.
- Delete the last 3 characters in S (abc), so S = "".
- Append xy to S, so S = "xy".
- Print the 2nd character on a new line. Currently, the 2nd character is y.
- Undo the last update to S, making S empty again (i.e., S = "").
- Undo the next to last update to S (the deletion of the last 3 characters), making S = "abc".
- Print the 1st character on a new line. Currently, the 1st character is a.
간단한 텍스트 편집기를 구현하세요. 이 편집기에는 처음에 빈 문자열 S가 들어 있습니다. 다음의 4가지 유형의 연산 중 Q개의 연산을 수행하세요.
- append(W) - 문자열 W를 S의 끝에 추가합니다.
- delete(k) - S의 마지막 k 문자를 삭제합니다.
- print(k) - S의 k번째 문자를 출력합니다.
- undo - 마지막으로 수행된 1번 또는 2번 유형의 연산을 취소하여 S를 그 연산 이전 상태로 되돌립니다.
예제
S = 'abcde'
ops = ['1 fg', '3 6', '2 5', '4', '3 7', '4', '3 4']
연산 인덱스 | S | ops[연산 인덱스] | 설명 |
0 | abcde | 1 fg | 문자열 fg 추가 |
1 | abcdefg | 3 6 | 6번째 문자 출력 (f) |
2 | abcdefg | 2 5 | 마지막 5 문자 삭제 (S = ab) |
3 | ab | 4 | 마지막 연산(삭제) 취소 (S = abcdefg로 복구) |
4 | abcdefg | 3 7 | 7번째 문자 출력 (g) |
5 | abcdefg | 4 | 마지막 연산(문자열 추가) 취소 (S = abcde로 복구) |
6 | abcde | 3 4 | 4번째 문자 출력 (d) |
입력 형식
첫 번째 줄에는 연산의 수를 나타내는 정수 Q가 주어집니다.
다음 Q개의 줄에는 각각의 연산을 나타내는 문자열이 주어집니다. 각 연산은 t로 시작하며, 필요한 경우 인수가 뒤에 붙습니다. 예를 들어 t = 1이고 W = "abcd"인 경우 1 abcd로 주어집니다.
제약 조건
- 1 ≤ Q ≤ 10^6
- 1 ≤ k ≤ |S|
- 모든 W의 총 길이 합은 10^6을 넘지 않습니다.
- 모든 삭제 연산의 k의 합은 2×10^6을 넘지 않습니다.
- 모든 입력 문자는 영어 소문자입니다.
- 주어진 연산 순서가 실행 가능한 순서로 주어집니다.
출력 형식
타입 3의 연산이 실행될 때마다 k번째 문자를 새 줄에 출력해야 합니다.
Solution
import java.io.*;
import java.util.*;
public class Solution {
public static void main(String[] args) {
// 입력을 읽고, 출력할 때 성능을 위해 BufferedReader와 StringBuilder 사용
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder output = new StringBuilder();
try {
int Q = Integer.parseInt(br.readLine());
StringBuilder S = new StringBuilder();
Stack<String> history = new Stack<>();
for (int i = 0; i < Q; i++) {
String[] operation = br.readLine().split(" ");
int opType = Integer.parseInt(operation[0]);
if (opType == 1) {
// append(W)
history.push(S.toString());
String W = operation[1];
S.append(W);
} else if (opType == 2) {
// delete(k)
history.push(S.toString());
int k = Integer.parseInt(operation[1]);
S.delete(S.length() - k, S.length());
} else if (opType == 3) {
// print(k)
int k = Integer.parseInt(operation[1]);
output.append(S.charAt(k - 1)).append("\n");
} else if (opType == 4) {
// undo
S = new StringBuilder(history.pop());
}
}
// 결과 출력
System.out.print(output.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
- BufferedReader와 StringBuilder를 사용하여 효율적으로 입력을 읽고 출력을 관리합니다.
- history 스택을 사용하여 append와 delete 연산을 수행하기 전의 상태를 저장해 undo 시 쉽게 복구할 수 있습니다.
- S는 StringBuilder로 관리하여 문자열을 효율적으로 조작하며, 연산의 결과는 최종적으로 output에 저장해 한 번에 출력합니다.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder output = new StringBuilder();
- 기능: BufferedReader와 StringBuilder 객체를 생성합니다.
- 사용 이유: BufferedReader는 콘솔로부터 효율적으로 입력을 읽어오는 데 사용되며, StringBuilder는 여러 줄의 출력을 하나로 모아 빠르게 출력하기 위해 사용됩니다.
int Q = Integer.parseInt(br.readLine());
- 기능: Q는 수행할 명령어의 개수를 나타내는 정수입니다.
- 사용 이유: 반복문에서 Q만큼 명령을 수행하기 위해 명령 수를 저장합니다.
StringBuilder S = new StringBuilder();
Stack<String> history = new Stack<>();
- 기능: S는 현재 문자열을 나타내고, history는 undo 기능을 위한 스택입니다.
- 사용 이유: S는 문자열의 현재 상태를 저장하며, history 스택은 문자열의 이전 상태를 저장하여 undo 명령 시 이전 상태로 돌아갈 수 있도록 합니다.
String[] operation = br.readLine().split(" ");
int opType = Integer.parseInt(operation[0]);
- 기능: 현재 명령어를 읽어 공백 기준으로 분리하고, 명령어의 타입을 확인합니다.
- 사용 이유: 명령어의 종류(opType)를 구분해 각 기능을 수행할 수 있도록 합니다.
append(W) 연산
if (opType == 1) {
history.push(S.toString());
String W = operation[1];
S.append(W);
}
- 기능: 문자열 W를 S의 끝에 추가합니다.
- 사용 이유: 새 문자열을 추가하기 전 history에 현재 문자열 상태를 저장하여 undo 시 이전 상태로 돌아갈 수 있게 합니다.
delete(k) 연산
else if (opType == 2) {
history.push(S.toString());
int k = Integer.parseInt(operation[1]);
S.delete(S.length() - k, S.length());
}
- 기능: S의 마지막 k개의 문자를 삭제합니다.
- 사용 이유: 삭제 전 상태를 history에 저장하여 undo 시 복원할 수 있도록 합니다
print(k) 연산
else if (opType == 3) {
int k = Integer.parseInt(operation[1]);
output.append(S.charAt(k - 1)).append("\n");
}
- 기능: 문자열 S에서 k번째 문자를 output에 추가합니다.
- 사용 이유: 지정된 위치의 문자만을 출력하기 위해 사용하며, output을 모아 한 번에 출력하는 방식을 취합니다.
undo 연산
else if (opType == 4) {
S = new StringBuilder(history.pop());
}
- 기능: 마지막 append 또는 delete 연산을 되돌립니다.
- 사용 이유: 이전 상태를 history 스택에서 꺼내어 S에 복원하여 undo 기능을 구현합니다.
} catch (IOException e) {
e.printStackTrace();
}
- 기능: 입출력 예외가 발생할 경우 예외 메시지를 출력합니다.
- 사용 이유: BufferedReader 사용 시 발생할 수 있는 예외를 처리하여 프로그램이 비정상 종료되지 않도록 합니다.
'코딩 테스트' 카테고리의 다른 글
[HackerRank] Jesse and Cookies (0) | 2024.11.10 |
---|---|
[HackerRank] Lego Blocks (7) | 2024.11.08 |
[HackerRank] Pairs (0) | 2024.11.07 |
[HackerRank] Balanced Brackets (4) | 2024.11.07 |
[HackerRank] Queue using Two Stacks (6) | 2024.11.06 |