본문 바로가기
Baekjoon/[1] 자료구조

[백준] 17299번 오등큰수 JAVA (자바) 풀이

by Poorm 푸름 2023. 7. 1.

문제 17299번

 :  크기가 N인 수열 A = A1, A2, ..., AN이 있다. 수열의 각 원소 Ai에 대해서 오등큰수 NGF(i)를 구해라

 :  Ai가 수열 A에서 등장한 횟수를 F

 :  Ai의 오등큰수는 오른쪽에 있으면서 F가 큰 수 중에서 가장 왼쪽에 있는 수를 의미한다

 :  그러한 수가 없는 경우에 오등큰수는 -1

 

 

  (예시)

    A = [3, 5, 2, 7]인 경우 NGE(1) = 5, NGE(2) = 7, NGE(3) = 7, NGE(4) = -1
    A = [9, 5, 4, 8]인 경우 NGE(1) = -1, NGE(2) = 8, NGE(3) = 8, NGE(4) = -1이다.

 
 

 [입력]

  

 :  첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)

 :  둘째에 수열 A의 원소 A1, A2, ..., AN (1 ≤ Ai ≤ 1,000,000)

 

 [출력]


 :  총 N개의 수 오등큰수를 공백으로 구분해 출력

 

 [문제 이해]

 

 : 오등큰수는 count가 아니다 수열 안에 있는 숫자 넣어줘야 한다

 :  문제푸는 방식을 외워야 한다

    무조건 스택 안의 peek값과 다음 수열을 비교한다


 :  오큰수와 다른점은 peek값과 다음수열을 비교하는 것이 아닌 다음 수열의 count 값을 비교하는 것이다


 :  count란 수열안에 같은 숫자가 몇회 반복되어 나왔는지의 횟수를 의미한다

 

 :  비교해봐서 오큰등수 못구하면 더 비교하지말고 push한 다음 바로 다음 것들끼리 다시 비교한다

    그리고나서 그다음번에 오큰등수를 구하게 되면 해당 수열을 pop하고

    이전에 못구했던 숫자들을 하나씩 다시 비교하면 된다

 

 :  더이상의 비교대상이 없을 때까지 비교한 뒤 마지막 수열에 남는 것들은 -1 처리해준다

 

  <그림설명>

 

수열 1 1 2 3 2 1
Index 0 1 2 3 4 5
count 3 2 1      

- 수열 순서대로 count 센 것

- 1부터 나왔으니 총 개수 3개, 다음 2 나왔으니 총 개수 2개, 다음 1 나왔으니 총 개수 1

 

 

1단계 2단계 3단계 4단계 5단계 6단계 7단계 8단계 9단계
                 
      3   4      
    2 2 2 2 2   5
  1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0

 * 이 스택에 들어가는 수는 수열이 아닌 Index 이다  

 

단계 1)

처음에는 스택에 아무 것도 없어서 일단 Index 0 번을 넣고 시작 (오큰수랑 같다)

사실상 Index 0 을 가진 1 이다

 

단계2)

스택의 peek인 Index 0과 옆의 수 Index 1 이자 1의 count를 비교한다 

둘다 1이기 때문에 횟수 즉 count 가 같다

오등큰수를 구할 수 없으므로 일단 Index 1을 push 하고 그 다음으로 넘어간다

 

단계3)

스택의 peek인 Index 1과 옆의 수 Index 2 이자 2의 count를 비교한다 

Index 2의 count가 더 작으므로 오등큰수를 구할 수 없다

Index 2를 push하고 다음으로 넘어간다

 

단계4)

스택의 peek인 Index 2와 옆의 수 Index 3 이자 3의 count를 비교한다 

Index 3의 count가 더 작으므로 오등큰수를 구할 수 없다

Index 3을 push하고 다음으로 넘어간다

 

단계5)

스택의 peek인 Index 3과 옆의 수 Index 4 이자 2의 count를 비교한다 

Index 4의 count가 더 크므로 오등큰수를 구할 수 있다 이때 Index4의 count 는 2 이다

고로 Index 3의 오등큰수는 2이다

Index 3은 다썼으니 pop하고 다음으로 넘어간다

 

단계6)

스택의 peek인 Index 2와 이어서 아까 비교하던 수 Index 4이자 2의 count를 비교한다 

둘다 2이기 때문에 횟수 즉 count 가 같다

오등큰수를 구할 수 없으므로 일단 Index 4를 push 하고 그 다음으로 넘어간다

 

단계7)

스택의 peek인 Index 4과 옆의 수 Index 5이자 1의 count를 비교한다 

Index 5의 count가 더 크므로 오등큰수를 구할 수 있다 이때 Index 5의 count는 3 이다

고로 Index 4의 오등큰수는 1이다

Index 4은 다썼으니 pop하고 다음으로 넘어간다

 

단계8)

스택의 peek인 Index 2와 이어서 아까 비교하던 수 Index 5이자 1의 count를 비교한다 

Index 5의 count가 더 크므로 오등큰수를 구할 수 있다 이때 Index 5의 count는 3 이다

고로 Index 2의 오등큰수는 1이다

Index 2는 다썼으니 pop하고 다음으로 넘어간다

 

단계9)

스택의 peek인 Index 1과 이어서 아까 비교하던 수 Index 5이자 1의 count를 비교한다 

둘다 1이기 때문에 횟수 즉 count 가 같다

오등큰수를 구할 수 없으므로 일단 Index 5를 push 하고 그 다음으로 넘어간다

 

단계10)

이제 더이상 비교할 수가 남아있지 않으므로 스택 안의 모든 수를 -1로 출력한다

 

 

오   등   큰   수      결     과
- 1 - 1  1 2 1 - 1
단계 10 참고 단계 10 참고 단계 8 참고 단계 5 참고 단계 7 참고 단계 10 참고

 

 [스택 연산]

 

  push(e)  스택의 맨 위에 요소 e 추가
  pop()  스택의 맨 위 요소를 삭제
  peek(s)  스택의 맨 위 요소를 삭제하지 않고 반환
  top()  스택 맨 위에 있는 데이터 값 반환
  isEmpty()  스택에 원소가 없으면 'True', 있으면 'False' 값 반환
  isFull()  스택에 원소가 없으면 'False', 있으면 'True' 값 반환

 

 [코드]

 

import java.io.*;
import java.util.*;
public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new 	OutputStreamWriter(System.out));
		Stack<Integer> stack = new Stack<>();
		int n = Integer.parseInt(br.readLine());
		int[] arr = new int[n];
		String[] input = br.readLine().split(" ");
                int count[] = new int[1000001]; //횟수담기
 
		for(int i = 0; i < n; i++){
			arr[i] = Integer.parseInt(input[i]);
                        count[arr[i]]+=1; // 카운트의 같은 배열이면 +1씩 증가
                }
		
		for(int i = 0; i < n; i++) {
			while(!stack.isEmpty() && count[arr[stack.peek()]] < count[arr[i]]) {
                            arr[stack.pop()] = arr[i];
			}
			stack.push(i); //오큰수랑 같다
                }
		
		while(!stack.isEmpty())
			arr[stack.pop()] = -1;
		
		for(int i = 0; i < n; i++)
			bw.write(arr[i]+" ");
		
        bw.flush();
	return;
    }
}

 

 [해설]

 :  Stack<Integer> stack = new Stack<>();  스택선언

 :  int n = Integer.parseInt(br.readLine());  첫째줄 개수 입력받기

 :  int[] arr = new int[n];  수열 담을 배열 선언

 :  int count[] = new int[1000001];  횟수담기

 :  String[] input = br.readLine().split(" ");  두번째 줄 공백으로 구분하기

    다른 표현1)
    StringTokenizer st = new StringTokenizer(br.readLine, " ")
     
    다른 표현2)
    String s = br.readLine();
    String spt[] = s.split(" ");
        
 :  for(int i = 0; i < n; i++){
               arr[i] = Integer.parseInt(input[i]);  입력들 배열에 담는게 제일 먼저다
               count[arr[i]]+=1;  같은 수들끼리의 count +1씩 증가
     }

 :  for(int i = 0; i < n; i++) {
              while(!stack.isEmpty() && count[arr[stack.peek()]] < count[arr[i]]) {
                    오큰수는 스택의 peek와 그다음 수열을 비교했지만
                    오등큰수는 스택 peek의 count와 그 다음 수열의 count를 비교한다
                          arr[stack.pop()] = arr[i]; 해당수열 빼고 오등큰수로 바꾸기
             }            
             stack.push(i);  다음 인덱스 추가하기 (오큰수랑 같다)
    }

 :  while(!stack.isEmpty())
             arr[stack.pop()] = -1;  마지막으로 스택 안에 남은 애들 -1로 바꿔주기 (오큰수랑 같다)

 :  for(int i = 0; i < n; i++)
             bw.write(arr[i]+" ");  출력하기
            

 

이제 풀어보러 갈께요 :)

 

 

https://www.acmicpc.net/problem/17299

 

17299번: 오등큰수

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째에 수열 A의 원소 A1, A2, ..., AN (1 ≤ Ai ≤ 1,000,000)이 주어진다.

www.acmicpc.net

 

* 독학으로 익히는 코딩이라 틀린 것이 있을 수 있습니다. 오류가 있다면 댓글을 통해 알려주세요. 감사합니다. *