배열로 풀면안되는 문제다. 왜냐하면 문자열이 n개고 명령어가 m개일때 매번 대략n개정도의 이동이 m번일어난다고 가정할때 nm정도의 연산이 필요한데 그럼 1억번을 넘기기 때문이다.
배열말고 연결리스트로 구현해야할듯하다.
String input[] = {"A", "B"};
input[0] =="A" false
char ch[] = {'a', 'b'};
ch[0] == 'a' true
String은 wrapper class라 비교할때 주솟값을 비교, char은 기본타입이라 값자체를 비교
n*m
을하면 천만번을 넘기게 된다. LinkedList<Character> list = new LinkedList();
char[] ch = str.toCharArray();
//ListIterator<Character> iter = list.listIterator();여기에 두면
// ConcurrentModificationException 뜸
for(int i=0;i<ch.length;i++){
list.add(ch[i]);
}
ListIterator<Character> iter = list.listIterator();
while(iter.hasNext()){
iter.next();//ConcurrentModificationException
}
list에 추가한 뒤에 선언해야
ConcurrentModificationException이 안뜬다
왜그런것일까?
자바의 컬렉션 프레임워크에서 컬렉션에 저장되어 있는 요소들을 읽어오는 방법을 표준화한 것이다.
hasNext()
→ 다음 요소가 존재하는지 혹은 그렇지 않은지 true/false로 리턴한다. true 이면 다음 요소다 있다는 것이고, false 이면 현재 요소가 마지막이라는 뜻이다.
next()
→ 다음 요소를 가져온다.
remove()
→ next()로 호출된 요소를 제거한다.
while(itr.hasNext()){
System.out.println("itr.next()==>" + itr.next()); // 다음 요소 출력
itr.remove(); // 다음 요소 삭제
}
while(itr.hasNext()){
itr.remove(); // 다음 요소 삭제
System.out.println("itr.next()==>" + itr.next()); // 다음 요소 호출(에러)
}
//IllegalStateException
next로 가리키고있는것을 삭제하고 그 next를 출력했기때문.
Iterator는 hasNext, next, remove 메서드 세개밖에 없는데
ListIterator는 데이터를 추가/교체가 가능하다
아이디어: stack 두개를 이용하여 구현 + bw사용
import java.io.*;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;
public class Main{
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//이코드에서 bw만 System.out.println을 쓰면 시간초과뜸
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String str = br.readLine();
int n = Integer.parseInt(br.readLine());
//커서기준으로 왼쪽에있는 요소들을 담을 stack
//stack을 이용해 구현하면 삽입/삭제가 o(1)만에 일어난다.
//이 문제는 o(n)아래로 끝나야한다. 그래서 n번반복안에는 n번또 반복하는 코드가 들어가선안된다.
Stack<Character> leftStack = new Stack<>();
Stack<Character> rightStack = new Stack<>();
//string을 char로 쪼개서 stack에 넣는다
//커서는 가장끝에 위치하니 커서기준왼쪽을 의미하는 leftStack에 요소들을 모두 넣어주면된다
for(int i=0;i<str.length();i++){
leftStack.push(str.charAt(i));
}
//n번 명령어를 입력받을 것이디ㅏ
for(int i=0;i<n;i++){
//명령어는 띄어쓰기로 구분된다
String[] input = br.readLine().split(" ");
if(input[0].equals("P")) {
//input[1]을 커서 왼쪽에 추가
leftStack.push(input[1].toCharArray()[0]);
}
else if(input[0].equals("B")){
//커서왼쪽삭제, 단 만약 stack이 비어있는 경우엔 pop하면 error난다
if(!leftStack.isEmpty()) leftStack.pop();
}
else if(input[0].equals("D")){
//커서 오른쪽으로 한칸
//pop하기전에는 항상 empty를 체크해준다
if(!rightStack.isEmpty()){
//커서가 오른쪽으로 간다는것은 커서기준 오른쪽에있던 요소가 왼쪽으로 이동함을 의미한다
char c = rightStack.pop();
leftStack.push(c);
}
}
else if(input[0].equals("L")){
//커서 왼쪽으로 한칸
if(!leftStack.isEmpty()){
char c = leftStack.pop();
rightStack.push(c);
}
}
}
//leftstack에있는것을 빼서 rightstack에 넣고 rightstack에서 pop해서 출력하면
//순서대로 출력이 가능해지게 된다
while(!leftStack.isEmpty()){
char c = leftStack.pop();
rightStack.push(c);
}
while(!rightStack.isEmpty()){
bw.write(rightStack.pop());
}
bw.flush();
bw.close();
}
}
stack 이용
push할때마다 top과 비교하여 만약 내가 넣으려는수가 top보다 크다면 while문을 통해서 stack에있는 모든 수를 하나씩 꺼내고
그 수의 오큰수를 push하려는 값으로 설정해준다
(1회연산의 여러개의 오큰수를 처리)
그리고 n번의 연산끝에 남은 것들은 다 -1로 처리해주면되니 o(n)으로 끝날 수 있다
import java.io.*;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;
public class Main{
//인덱스와 값을 저장하고, 이를 스택으로넣으려고구현함
//그냥 값만 넣어버리면 넣는순간 인덱스를 모르기때문에 아래의 class가 필요함
public static class Node{
int idx;
int value;
public Node(int idx, int val){
this.idx = idx;
this.value = val;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int n = Integer.parseInt(br.readLine());
String input[] = br.readLine().split(" ");
Stack<Node> stack = new Stack<>();
//i번째수에 i번째수의 값을 저장
//i번째 수에 i번째수의 오큰수를 저장
int o[] = new int[n+1];
for(int i=1;i<=n;i++){
//입력으로 들어오는 값
int val = Integer.parseInt(input[i-1]);
//stack이 비어있지 않아야함. 비어있으면 peek참조가 불가능하기때문
//peek의 value가 새로들어온 입력값보다 작은 경우에만 반복문을 돌린다
//stack에 쌓여잇는 값을 하나씩 빼서
//stack에서뺀값의 오큰수는 새로들어오는 큰수 가 되는것이다
while(!stack.isEmpty()&&stack.peek().value<val){
Node node = stack.pop();
o[node.idx] = val;
}
//stack에 들어있따는것은 아직오큰수를 찾지 못했다는 의미이다.
//새로운 값은 이전값들보다 크긴했지만 이 크수보다 더 큰 오큰수는 찾지 못했으므로 일단 stack에 추가한다
stack.push(new Node(i, val));
}
//stack에 들어있는 값들은 모두 오큰수가 없는 값들이므로 -1으로 초기화해준다
while(!stack.isEmpty()){
o[stack.pop().idx] = -1;
}
//배열에 있는값을 그대로 출력하면 맨처음에 입력받은 순서대로 오큰수를 출력할수있게된다
for(int i=1;i<=n;i++){
bw.write(o[i] + " ");
}
bw.flush();
bw.close();
}
}
출처
https://thefif19wlsvy.tistory.com/41
https://tragramming.tistory.com/100