https://softeer.ai/practice/6250
각 대회별로 점수를 정렬해두고.
모든 대회, 모든 참가자에 대해서 아래 작업을 해준다.
c 대회의 i참가자의 점수를 key값으로 lowerBound나 upperBound의 index를 구하면 된다.
정렬 => 이진탐색
정렬 => 맵핑
정렬한 배열을 순회하면서 값을 선택하자.
선택한 값이 이전에 선택한 값마다 달라질때마다,
다시 말해서 바뀔때마다 현재 값(key)과 현재 인덱스(value)를 매핑한다.
0번 인덱스의 값은 static하게 초기화해두자.
import java.io.*;
import java.util.*;
// System.out.println();
public class Main {
// 고정
static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokens;
static StringBuilder output = new StringBuilder();
// 세팅
// 메인
public static void main(String[] args) throws Exception {
// 입력
int N = Integer.parseInt(input.readLine());
// 배열 세팅
int[][] originalArr = new int[4][N];
int[][] sortedArr = new int[4][N];
Arrays.fill(sortedArr[3], 0);
// 배열 초기화
for(int round=0; round<3; round++){
tokens = new StringTokenizer(input.readLine());
for(int i=0; i < N; i++){
int score = Integer.parseInt(tokens.nextToken());
originalArr[round][i] += score;
originalArr[3][i] += score;
sortedArr[round][i] = score;
sortedArr[3][i] += score;
}
}
// 세팅
//// 정렬용 배열 정렬
for(int i=0; i < 4; i++){
Arrays.sort(sortedArr[i]);
}
// 작업
// Map 채우기.
Map<Integer, Integer> [] score_rankMapArr = new HashMap[4];
for(int r=0; r < 4; r++){
score_rankMapArr[r] = new HashMap();
}
for(int r=0; r < 4; r++){
int coin = sortedArr[r][0];
for(int i=0; i < N; i++){
if(coin != sortedArr[r][i]){
// score가 coin 이하인 사람의 수가 i명 있다. => score가 coin보다 높은 사람의 수는 N-i명이다. => score가 coin인 사람의 등수는 N-i+1 이다.
score_rankMapArr[r].put(coin, N-i+1);
// coin 값이 바뀌는 구간에 맞게 coin값 변경.
coin = sortedArr[r][i];
}
}
// 맨 마지막 coin 값은 바뀔일 없으므로 if 문에 안 걸린다. 따라서 따로 작업해준다. 참고로 맨 마지막 coin 값은 1등 값이다.
score_rankMapArr[r].put(sortedArr[r][N-1], 1);
}
for(int r=0; r < 4; r++){ // 각 대회별로
for(int i=0; i < N; i++){ // 각 참가자에 대해서
int rankKey = originalArr[r][i];
output.append(score_rankMapArr[r].get(rankKey)).append(" ");
}
// 대회 끝나면 줄 바꿈
output.append("\n");
}
// 출력
System.out.println(output);
// System.out.println(Arrays.deepToString(sortedArr));
}
}
내림차순으로 정렬하고 lowerBound 찾기
오름차순으로 정렬하고 upperBound 찾기
package softeer;
import java.io.*;
import java.util.*;
public class P_2025_0302_01_오름차순_upper_binarySearch_while {
// 고정
static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokens;
static StringBuilder output = new StringBuilder();
// 세팅
static int[][] originalArr;
static int[][] sortedArr;
// 메인
public static void main(String[] args) throws Exception {
// 입력
int N = Integer.parseInt(input.readLine());
// 배열 세팅
originalArr = new int[4][N];
sortedArr = new int[4][N];
// 배열 초기화
for(int round=0; round < 3; round++){
tokens = new StringTokenizer(input.readLine());
for (int i = 0; i < N; i++) {
int score = Integer.parseInt(tokens.nextToken());
originalArr[round][i] += score;
originalArr[3][i] += score;
sortedArr[round][i] += score;
sortedArr[3][i] += score;
}
}
// 세팅
//// 정렬용 배열 정렬
for(int i=0; i < 4; i++){
Arrays.sort(sortedArr[i]);
}
// 작업
for(int r=0; r < 4; r++){ // 각 대회별로
for(int i=0; i < N; i++){ // 각 참가자에 대해서
int rankKey = originalArr[r][i];
//int left, int right, int fineMid, final int round, final int rankKey
int left = 0;
int right = N-1;
int upperBound=0;
while(left <= right){
int mid = left + (right-left)/2;
if(sortedArr[r][mid] == rankKey){
upperBound = mid;
left = mid+1;
} else if (sortedArr[r][mid] > rankKey) {
right = mid-1;
} else{
left = mid +1;
}
}
int rank = N - (upperBound+1) +1;
output.append(rank).append(" ");
}
// 대회 끝나면 줄 바꿈
output.append("\n");
}
// 출력
System.out.println(output);
}
}
package softeer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class P_2025_0302_01_오름차순_upper_binarySearch_method {
// 고정
static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokens;
static StringBuilder output = new StringBuilder();
// 세팅
static int[][] originalArr;
static int[][] sortedArr;
// 메인
public static void main(String[] args) throws Exception {
// 입력
int N = Integer.parseInt(input.readLine());
// 배열 세팅
originalArr = new int[4][N];
sortedArr = new int[4][N];
// 배열 초기화
for(int round=0; round < 3; round++){
tokens = new StringTokenizer(input.readLine());
for (int i = 0; i < N; i++) {
int score = Integer.parseInt(tokens.nextToken());
originalArr[round][i] += score;
originalArr[3][i] += score;
sortedArr[round][i] += score;
sortedArr[3][i] += score;
}
}
// 세팅
//// 정렬용 배열 정렬
for(int i=0; i < 4; i++){
Arrays.sort(sortedArr[i]);
}
// 작업
for(int r=0; r < 4; r++){ // 각 대회별로
for(int i=0; i < N; i++){ // 각 참가자에 대해서
int rankKey = originalArr[r][i];
//int left, int right, int fineMid, final int round, final int rankKey
bs(0,N-1,0,r,rankKey);
}
// 대회 끝나면 줄 바꿈
output.append("\n");
}
// 출력
System.out.println(output);
}
// 메소드
static void bs(int left, int right, int fineMid, final int round, final int rankKey){ //
// 바닥조건
if(left>right){
// 작업
int rank = sortedArr[round].length - (fineMid+1) +1; // 전체 - 나 이하 = 나보다 등수 높은 사람의 수
output.append(rank).append(" ");
return;
}
// 재귀파트
int mid = left + (right-left)/2;
if( sortedArr[round][mid] == rankKey){
bs(mid+1, right, mid, round, rankKey); // 쓸수있는 mid값 나올때마다 fineMid 갱신해서 parameter로 넘겨주면서 관리하기.
} else if ( sortedArr[round][mid] < rankKey ) {
bs(mid+1, right, fineMid, round, rankKey);
} else{
bs(left, mid-1, fineMid, round, rankKey);
}
}
}
package softeer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.StringTokenizer;
public class P_2025_0302_01_내림차순_lower_binarySearch_method {
// 고정
static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokens;
static StringBuilder output = new StringBuilder();
// 세팅
static int[][] originalArr;
static Integer[][] sortedArr;
// 메인
public static void main(String[] args) throws Exception {
// 입력
int N = Integer.parseInt(input.readLine());
// 배열 세팅
originalArr = new int[4][N];
sortedArr = new Integer[4][N];
for (int i = 0; i < 4; i++) {
Arrays.fill(sortedArr[i], 0);
}
// 배열 초기화
for(int round=0; round < 3; round++){
tokens = new StringTokenizer(input.readLine());
for (int i = 0; i < N; i++) {
int score = Integer.parseInt(tokens.nextToken());
originalArr[round][i] += score;
originalArr[3][i] += score;
sortedArr[round][i] += score;
sortedArr[3][i] += score;
}
}
// 세팅
//// 정렬용 배열 정렬
for(int i=0; i < 4; i++){
Arrays.sort(sortedArr[i], Collections.reverseOrder());
}
// 작업
for(int r=0; r < 4; r++){ // 각 대회별로
for(int i=0; i < N; i++){ // 각 참가자에 대해서
int rankKey = originalArr[r][i];
//int left, int right, int fineMid, final int round, final int rankKey
bs(0,N-1,0,r,rankKey);
}
// 대회 끝나면 줄 바꿈
output.append("\n");
}
// 출력
System.out.println(output);
}
// 메소드
static void bs(int left, int right, int fineMid, final int round, final int rankKey){ //
// 바닥조건
if(left>right){
// 작업
int rank = fineMid+1; // 전체 - 나 이하 = 나보다 등수 높은 사람의 수
output.append(rank).append(" ");
return;
}
// 재귀파트
int mid = left + (right-left)/2;
if( sortedArr[round][mid] == rankKey){
bs(left, mid-1, mid, round, rankKey); // 쓸수있는 mid값 나올때마다 fineMid 갱신해서 parameter로 넘겨주면서 관리하기.
} else if ( sortedArr[round][mid] < rankKey ) {
bs(left, mid-1, fineMid, round, rankKey);
} else{
bs(mid+1, right, fineMid, round, rankKey);
}
}
}
[
44.58 MB
|580 ms
]
문제를 풀며 했던 실수나 약점에 대해 정리하는게 좋을것 같다.
- IDE 없는 환경에서 풀어서 컴파일 에러나 변수명 자동완성이 없어서, 코딩 퍼포먼스가 너무 떨어진다. 휴먼에러 리스크가 커져서, 좀 더 높은 집중력이 요구된다. 이번처럼 실전같은 환경에서 연습을 더 하자.
- 궁색한 이야기지만 처음 가본 카페에서 주변이 너무 산만해서 집중력이 안 좋았다.
- 그래서 입력값의 한줄 한줄이 참가자의 성적인 줄 알았다.
다시말해서, (참가자)(대회)인줄 알았는데 사실은 (대회)(참가자)였다.- 재귀 함수의 바닥 조건에서 return을 빼먹었다. IDE에 감사하자.
- bs()의 전체 탐색 범위를 0~N-1로 해야하는데, 등수라고 잘못 생각해서 1~N으로 해버렸다.
- bs()에서 탐색범위를 좁히는 방향을 결정할때, 오름차순으로 정렬했다고 착각했다. 처음풀때는 내림차순으로 정렬하는 방식으로 시도했는데...
- 내림차순으로 정렬하는게 오름차순으로 정렬하는 것보다 대략 2.X배 느리다. Collercions.reverseOrder()가 범인인것 같다.