문제

N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다.

N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. (1 ≤ N < 15)

출력

첫째 줄에 퀸 N개를 서로 공격할 수 없게 놓는 경우의 수를 출력한다.

나의 풀이

 n퀸의 문제는 기본 알고리즘에 대해 배울때 이미 한 번 익혔던 알고리즘이라 접근법은 기억하고 있는 방법으로 했다. 체스판의 1번째 부터 n번째 행까지 퀸을 놓으면서 이전 행과 퀸이 겹치지 않는지 체크하면서 모든 경우의 수를 놓아보도록 하고 성공할때마다 count를 1씩 증가시켜준다. 이번 풀이는 다른 부분은 직접 작성한 코드인데 다른 사람 풀이중에서 이전 행과 퀸이 겹치지 않는지 파악하는 조건이 좀 신선한 풀이가 있길래 가져다가 적용해보았다.

 

코드

import java.util.*;
import java.io.*;

public class Main {
    public static int count;
    public static boolean isPoss(int[] board, int row) {
        for(int i=1; i<row; i++) {
            if(board[i] == board[row]) //다른 행에 같은 열이 있는 경우.
                return false;
            if(Math.abs(i-row)==Math.abs(board[i]-board[row])) //대각 선상 있는 경우.
                return false;
        }
        return true;
    }
    
    public static void dfs(int[] board, int n, int row) {
        if(row==n){ //현재 행이 체스판 마지막 행인 경우 리턴
            count++;
            return;
        }
        row++;//다음행 선택
        for(int i=1; i<=n; i++) {
            board[row] = i; //다음행에 일단 i번째 열에 퀸을 넣어보고 체크한다.
            if(isPoss(board, row)) //다음행 i번째 퀸을 놓을 수 있으면 놓고, 그 다음행으로 넘어간다.
                dfs(board, n, row);
        }
            
        
    }
    
    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());
        int[] board;
        count = 0;
        
        for(int i=1; i<=n; i++) {
            board = new int[n+1]; // 1~n행 크기의 체스판을 생성한다.
            board[1] = i; //체스판의 1번째 줄(행) 중에서 i열 위치에 퀸을 놓고 시작한다.
            dfs(board, n, 1);
        }
        
        
        bw.write(count+"\n");
        bw.flush();
    }
}

'Baekjoon-Algorithm > 백트래킹' 카테고리의 다른 글

백준 2580 스도쿠 java 풀이  (0) 2020.08.25

문제 설명

아래와 같이 5와 사칙연산만으로 12를 표현할 수 있습니다.

12 = 5 + 5 + (5 / 5) + (5 / 5)
12 = 55 / 5 + 5 / 5
12 = (55 + 5) / 5

5를 사용한 횟수는 각각 6,5,4 입니다. 그리고 이중 가장 작은 경우는 4입니다.
이처럼 숫자 N과 number가 주어질 때, N과 사칙연산만 사용해서 표현 할 수 있는 방법 중 N 사용횟수의 최솟값을 return 하도록 solution 함수를 작성하세요.

제한사항

  • N은 1 이상 9 이하입니다.
  • number는 1 이상 32,000 이하입니다.
  • 수식에는 괄호와 사칙연산만 가능하며 나누기 연산에서 나머지는 무시합니다.
  • 최솟값이 8보다 크면 -1을 return 합니다.

나의 풀이

 이번 문제는 어려웠다.. 먼저 다이나믹 프로그래밍(DP) 개념에 대한공부가 선행되면 좋고, 이 문제는 효율성 테스트가 없고 최대 숫자의 갯수가 8개이기 때문에 DP가 아니라 전체를 스캔하며 답을 찾는 DFS, BFS 등의 방식으로도 풀 수는 있다. 하지만 문제 자체가 DP 분류에 있기 때문에 가능하면 DP로 풀어보고자 했는데... DP에 대한 개념은 이해를 했지만 문제풀이는 사실 실패해서 다른사람들의 풀이를 최대한 많이 찾아보고 디버깅해보면 풀었다. 어려웠던 점은 DP에 대한 개념보다는 주어진 숫자 N과 최소한의 횟수로 찾아야하는 수 number간의 식을 찾는게 어려웠다.

 

 이해한 바를 간단히 정리하자면

 숫자 N(5라고 가정)을 사용해서 만들 수 있는 수는

 

 N을 1번 사용했을땐 

    5

 

 N을 2번 사용했을땐

    55(N을 연속 2번)

    5(N을 1번 사용해서 만든수) *N

    5(N을 1번 사용해서 만든수) /N (단 나누는 수가 0이 아니여야한다.)

    5(N을 1번 사용해서 만든수) +N

    5(N을 1번 사용해서 만든수) -N

 

N을 3번 사용했을땐

   555(N을 3번 반복)

   5를 2번사용해서 만든수를 5로 사칙연산

 

이와같은 패턴이 반복되기 때문에 이를 반복 수행하되, DP인 만큼 외부에 Set으로 이뤄진 배열을 선언하고 저장하면서 실행하였다

 

 

 

코드

import java.util.*;

class Solution {
    static int tempN;
    TreeSet<Integer>[] arr;
    
    public TreeSet<Integer> getNum(int n) {
        if((arr[n]!=null) && !arr[n].isEmpty())
            return arr[n];
        
        int num = 0;
        for(int i=0; i<n ; i++)
            num = 10*num + tempN;
        
        TreeSet<Integer> temp = new TreeSet<>();
        temp.add(num);
        
        for(int i=1; i<n; i++) {
            int j = n-i;
            TreeSet<Integer> from = getNum(i);
            TreeSet<Integer> to = getNum(j);
            for(int n1 : from) {
                for(int n2 : to) {
                    temp.add(n1+n2);
                    temp.add(n1-n2);
                    temp.add(n1*n2);
                    if(n2!=0) temp.add(n1/n2);
                }
            }
        }
        return arr[n] = temp;
    }
    public int solution(int N, int number) {
        int answer = 0;
        tempN = N;
        arr = new TreeSet[10];
        for(int i=1; i<=8; i++) {
            getNum(i);
            if(arr[i].contains(number)) 
                return i;
        }
        
        return -1;
    }
}

 

문제 설명

고속도로를 이동하는 모든 차량이 고속도로를 이용하면서 단속용 카메라를 한 번은 만나도록 카메라를 설치하려고 합니다.

고속도로를 이동하는 차량의 경로 routes가 매개변수로 주어질 때, 모든 차량이 한 번은 단속용 카메라를 만나도록 하려면 최소 몇 대의 카메라를 설치해야 하는지를 return 하도록 solution 함수를 완성하세요.

제한사항

  • 차량의 대수는 1대 이상 10,000대 이하입니다.
  • routes에는 차량의 이동 경로가 포함되어 있으며 routes[i][0]에는 i번째 차량이 고속도로에 진입한 지점, routes[i][1]에는 i번째 차량이 고속도로에서 나간 지점이 적혀 있습니다.
  • 차량의 진입/진출 지점에 카메라가 설치되어 있어도 카메라를 만난것으로 간주합니다.
  • 차량의 진입 지점, 진출 지점은 -30,000 이상 30,000 이하입니다.

나의 풀이

 주어진 배열에서 입장하는 위치에 따라 배열을 정리하고, 하나씩 값을 꺼내면서 출구 위치 최소값을 저장했다. 저장된 최소 값보다 입장 위치가 더 크다면 겹치는 구간이 없다는 말이므로 카메라 갯수를 1씩 증가시킨다. 접근은 이렇게 하였는데, 구현을 나누어서 해보았다. 먼저는 배열 자체를 정렬해서 구현한게 코드1, 두 번째로는 객체를 생성하고 객체 배열을 만들어서 정렬하는 방식. 사실 어떻게 풀던 동일하고 실행시간도 크게 차이는 안났지만 비교값해야할 변수가 더 다양해질 경우와 객체를 이용하는 방식으로도 풀어보고 싶어서 괜한? 코드를 더 작성해봤다.

 

 

코드1

import java.util.*;
class Solution {
     public int solution(int[][] routes) {
        int answer = 0;
        Arrays.sort(routes, new Comparator<int[]>() {
            public int compare(int[] r1, int[] r2) {
                return r1[0] - r2[0];
            }
        });
         
         int max = Integer.MIN_VALUE;
         
         for(int i=0; i<routes.length; i++) {
             if(max >= routes[i][0]) {
                 if(max> routes[i][1])
                     max = routes[i][1];
                 continue;
             }
             max = routes[i][1];
             answer++;
         }
        
        return answer;
    }
    
    
}

 

코드2

import java.util.*;
class Solution {
    class Route implements Comparable<Route> {
        int in;
        int out;
        
        Route(int in, int out) {
            this.in = in;
            this.out = out;
        }
        
        @Override
        public int compareTo(Route r2) {
            if(this.in<r2.in) return -1;
            else if(this.in > r2.in) return 1;
            else {
                if((this.out-this.in) < (r2.out-r2.in)) return -1;
                else if((this.out-this.in) > (r2.out-r2.in)) return 1;
                else
                    return 0;
            }
        }
    }
    
    public int solution(int[][] routes) {
        int answer = 0;
        Route[] arr = new Route[routes.length];
        for(int i=0; i<routes.length; i++) {
            arr[i]  = new Route(routes[i][0], routes[i][1]);
        }
        
        Arrays.sort(arr);
        
        int min = arr[0].in;
        int max = arr[0].out;
        answer++;
        for(int i=1; i<arr.length; i++) {
            Route route = arr[i];
            if(route.in > max ) {
                answer++;
                min = route.in;
                max = route.out;
            } else {
                min = route.in;
                if(route.out<max) max = route.out; 
            }
        }
        
        return answer;
    }
    
    
}

문제 설명

n개의 섬 사이에 다리를 건설하는 비용(costs)이 주어질 때, 최소의 비용으로 모든 섬이 서로 통행 가능하도록 만들 때 필요한 최소 비용을 return 하도록 solution을 완성하세요.

다리를 여러 번 건너더라도, 도달할 수만 있으면 통행 가능하다고 봅니다. 예를 들어 A 섬과 B 섬 사이에 다리가 있고, B 섬과 C 섬 사이에 다리가 있으면 A 섬과 C 섬은 서로 통행 가능합니다.

제한사항

  • 섬의 개수 n은 1 이상 100 이하입니다.
  • costs의 길이는 ((n-1) * n) / 2이하입니다.
  • 임의의 i에 대해, costs[i][0] 와 costs[i] [1]에는 다리가 연결되는 두 섬의 번호가 들어있고, costs[i] [2]에는 이 두 섬을 연결하는 다리를 건설할 때 드는 비용입니다.
  • 같은 연결은 두 번 주어지지 않습니다. 또한 순서가 바뀌더라도 같은 연결로 봅니다. 즉 0과 1 사이를 연결하는 비용이 주어졌을 때, 1과 0의 비용이 주어지지 않습니다.
  • 모든 섬 사이의 다리 건설 비용이 주어지지 않습니다. 이 경우, 두 섬 사이의 건설이 불가능한 것으로 봅니다.
  • 연결할 수 없는 섬은 주어지지 않습니다.

나의 풀이

  문제의 이해 자체는 쉽다. 각 섬은 어떻게든 연결되어 있는데, 모든 섬을 연결할때 가장 작은 값을 구하면 되기 때문에 각 섬마다 가장 적은 비용의 연결점을 찾으면 되는 것. 하지만 코드로 구현하려니 이전 문제들에서 사용했던 dfs 방식이나 bfs을 그대로 적용할 순 없었다. 각 섬(노트) 간 연결비용이 다르기 때문.. 한참을 고민하고 코드도 작성해보다가 만난 것이 크루스칼 알고리즘이다. 이 알고리즘을 따로 공부하고 문제를 푸니 금방풀어서 좀 허망했던...

크루스칼 알고리즘 정리는 따로 올려야겠다.

코드

import java.util.*;

class Solution {
    class Edge implements Comparable<Edge> {
        int from, to, cost;
        Edge(int from, int to, int cost) {
            this.from = from;
            this.to = to;
            this.cost = cost;
        }
        
        @Override
        public int compareTo(Edge e2) {
            return this.cost - e2.cost;
        }
    }
    
    public int solution(int n, int[][] costs) {
        int answer = 0;
        int[] parent = new int[n];
        PriorityQueue<Edge> que = new PriorityQueue<>();
        for(int i=0; i<costs.length; i++) {
            que.offer(new Edge(costs[i][0], costs[i][1], costs[i][2]));
        }
        
        for(int i=0; i<n; i++) {
            parent[i] = i;
        }
        
        while(!que.isEmpty()) {
            Edge edge = que.poll();
            if(findParent(parent, edge.from) == findParent(parent, edge.to)) continue;
            union(parent, edge.from, edge.to);
            answer += edge.cost;
            
        }
        
        return answer;
    }
    
    public int findParent(int[] parent, int n) {
        if(parent[n]==n) return n;
        return parent[n] = findParent(parent, parent[n]);
    }
    
    public void union(int[] parent, int n1, int n2) {
        int rootN1 = findParent(parent, n1);
        int rootN2 = findParent(parent, n2);
        
        if(rootN1 != rootN2) parent[rootN2] = rootN1;
    }
}

문제 설명

무인도에 갇힌 사람들을 구명보트를 이용하여 구출하려고 합니다. 구명보트는 작아서 한 번에 최대 2명씩 밖에 탈 수 없고, 무게 제한도 있습니다.

예를 들어, 사람들의 몸무게가 [70kg, 50kg, 80kg, 50kg]이고 구명보트의 무게 제한이 100kg이라면 2번째 사람과 4번째 사람은 같이 탈 수 있지만 1번째 사람과 3번째 사람의 무게의 합은 150kg이므로 구명보트의 무게 제한을 초과하여 같이 탈 수 없습니다.

구명보트를 최대한 적게 사용하여 모든 사람을 구출하려고 합니다.

사람들의 몸무게를 담은 배열 people과 구명보트의 무게 제한 limit가 매개변수로 주어질 때, 모든 사람을 구출하기 위해 필요한 구명보트 개수의 최솟값을 return 하도록 solution 함수를 작성해주세요.

 

제한사항

  • 무인도에 갇힌 사람은 1명 이상 50,000명 이하입니다.
  • 각 사람의 몸무게는 40kg 이상 240kg 이하입니다.
  • 구명보트의 무게 제한은 40kg 이상 240kg 이하입니다.
  • 구명보트의 무게 제한은 항상 사람들의 몸무게 중 최댓값보다 크게 주어지므로 사람들을 구출할 수 없는 경우는 없습니다.

나의 풀이

 '몸무게가 가장 가벼운 사람은 몸무게가 가장 무거운 사람과 보트를 타야 최소한의 보트로 사람들을 태울 수 있다.' 라는 접근법으로 문제 풀이를 시작했다.

 코드2 풀이 탑승객들을 무게순으로 정렬해서 List에 담고 젤 가벼운 사람(index == 0)을 제일 무거운 사람부터 차례로 내려오며 무게를 더해보면서 주어지는 무게제한 이하가 발견되는 순간 List에서 remove해주는 식으로 코드를 작성했다. 결과 테스트는 통과했는데 효율성 테스트는 통과하지 못했다. 이 코드를 작성하면서도 굳이 리스트를 쓸 필요가 없겠는데 라는 생각을 하면서 작성했었기 때문에 바로 배열의 인덱스를 조작해서 코드1를 작성했다.

 코드1를 코드2와 같은 접근법으로 작성하려면 배열의 요소들을 조작하기가 복잡해져 효율성이 낮아진다 생각해서 접근법부터 다시 생각해 보았다. 그리고 새로운 접근법으로는 '제일 무거운 사람이 제일 가벼운사람과도 최대무게를 초과한다면 무조건 혼자타야 한다' 라는 접근법이었다. 결과적으로 가장 가벼운 사람으로 가장 무거운 사람부터 합을 무게제한과 비교해보면서, 무게제한을 초과하는 사람은 배열에서 제외하는 방식으로 생각보다 간단하게 배열 전체를 스캔할 수 있었다.

 

 

코드1

import java.util.*;

class Solution {
    public int solution(int[] people, int limit) {
        int answer = 0;
        Arrays.sort(people);
        int idx = people.length - 1;
        //이 for문에서는 최소 index=i번째 사람은 혼자던지 같이던지 무조건 보트를 탄다. 
        //따라서 매번 i와 answer이 1씩 증가.
        for(int i=0; i<=idx; i++, answer++) {
            //while문으로 index == idx는 혼자던지 index == i와 같이던지 무조건 보트를 타게된다. 
            //while문의 조건을 만족할 경우(무게초과) 혼자타고, 만족하지 못한다면 같이 타게된다. 
            while(i<idx && people[i]+people[idx--] > limit) {
                answer++;
            }
        }
        
        
        return answer;
    }
}

 

코드2

import java.util.*;

class Solution {
    public int solution(int[] people, int limit) {
        int answer = 0;
        
        List<Integer> list = new ArrayList<>();
        for(int n : people) {
            list.add(n);
        }
        Collections.sort(list);
        
        while(list.size()>0) {
            int temp = list.get(0);
            int idx = list.size()-1;
            while(idx>0) {
                if(list.get(idx)+temp > limit) {
                    idx--;
                    continue;
                }
                list.remove(idx);
                break;
            }
            answer++;
            list.remove(0);
        }
        
        return answer;
    }
}

문제 설명

 조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다. ( ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA )

 조이스틱을 각 방향으로 움직이면 아래와 같습니다.

 ▲ - 다음 알파벳 ▼ - 이전 알파벳 (A에서 아래쪽으로 이동하면 Z로) ◀ - 커서를 왼쪽으로 이동 (첫 번째 위치에서 왼쪽으로 이동하면 마지막 문자에 커서) ▶ - 커서를 오른쪽으로 이동

 예를 들어 아래의 방법으로 JAZ를 만들 수 있습니다.

  - 첫 번째 위치에서 조이스틱을 위로 9번 조작하여 J를 완성합니다. - 조이스틱을 왼쪽으로 1번 조작하여 커서를 마지막 문자 위치로 이동시킵니다. - 마지막 위치에서 조이스틱을 아래로 1번 조작하여 Z를 완성합니다. 따라서 11번 이동시켜 "JAZ"를 만들 수 있고, 이때가 최소 이동입니다.

 만들고자 하는 이름 name이 매개변수로 주어질 때, 이름에 대해 조이스틱 조작 횟수의 최솟값을 return 하도록 solution 함수를 만드세요.

 

제한 사항

  • name은 알파벳 대문자로만 이루어져 있습니다.
  • name의 길이는 1 이상 20 이하입니다.

 

나의 풀이

 이 문제에서 좀 헷갈린 부분이 오른쪽이나 왼쪽으로만 쭉 가야한다 생각을 하고 문제풀이를 시작했는데, 경우에 따라선 중간까진 오른쪽으로 가다가 Name의 뒷 부분은 다시 왼쪽으로 돌아가도 최소 경우의 수가 보였다. 결국 문제 접근을 다시 시작. 일단 각 자리에서 알파벳을 선택하는 부분은 자리 이동과 무관하게 고정되기 때문에 그 수를 전부 저장하고, 최소 자리 이동 횟수를 구했다. name의 각 자리까지 정주행 하다가, 남은 부분은 역주행이 필요할 경우 스틱의 이동 횟수를 계산하도록 하고, 기존의 최소 이동횟수(초기값을 정주행 할 경우 length -1 )와 비교해서 더 작은 값으로 갱신했다. 마지막으로 각 자리 알파벳 선택횟수 + 최소 자리 이동횟수를 던해서 리턴.

 코드를 생각하는 시간은 생각보다 얼마 안걸렸는데 문제 자체를 이해하는데 시간이 좀 걸렸던게 아쉽다.

 

import java.util.*;

class Solution {
    public int solution(String name) {
        int answer = 0;
        int alpha = 'Z'-'A'+1;
        
        //각 자리에서 위,아래로 최소 이동값
        for(int i=0; i<name.length(); i++) {
            int temp = name.charAt(i) - 'A';
            if(temp==0) continue;
            answer += Math.min(temp, alpha-temp);
        }
        
        //최소 자리 이동값
        int minCount = name.length()-1; //기본 이동거리는 길이 - 1
        for(int i=0; i<name.length(); i++) {
            if(name.charAt(i)=='A') continue;
            int check = i+1;
            while(check<name.length() && name.charAt(check)=='A') {
                check++;
            }
            int moveCount = i*2 + (name.length() - check); //현재위치+돌아갈거리 + 끝위치
            minCount = Math.min(minCount, moveCount);
        }
        
        return answer + minCount;
    }
}

문제 설명

 

매운 것을 좋아하는 Leo는 모든 음식의 스코빌 지수를 K 이상으로 만들고 싶습니다. 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 Leo는 스코빌 지수가 가장 낮은 두 개의 음식을 아래와 같이 특별한 방법으로 섞어 새로운 음식을 만듭니다.

섞은 음식의 스코빌 지수 = 가장 맵지 않은 음식의 스코빌 지수 + (두 번째로 맵지 않은 음식의 스코빌 지수 * 2)

Leo는 모든 음식의 스코빌 지수가 K 이상이 될 때까지 반복하여 섞습니다.
Leo가 가진 음식의 스코빌 지수를 담은 배열 scoville과 원하는 스코빌 지수 K가 주어질 때, 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 섞어야 하는 최소 횟수를 return 하도록 solution 함수를 작성해주세요.

 

제한 사항

  • scoville의 길이는 2 이상 1,000,000 이하입니다.
  • K는 0 이상 1,000,000,000 이하입니다.
  • scoville의 원소는 각각 0 이상 1,000,000 이하입니다.
  • 모든 음식의 스코빌 지수를 K 이상으로 만들 수 없는 경우에는 -1을 return 합니다.

나의 풀이

 일단 매 차수마다 가장 작은 두 값을 꺼내야 하는건 어쩔 수 없기에 어떻게 가장 작은 두 값을 찾는 것이 효율적인지가 관건이었다. 처음 작성한 코드1은 가장 작은 값 두 개를 꺼내기 위해 scoville 배열을 오름차순 정렬하고, 가장 작은 두 값을 계산해 배열에 넣고 배열을 자르는 작업을 반복하도록 하였다. 결과는 실행은 되지만 효율성 테스트 통과실패..

 다른 접근법으로 다른 컬렉션들을 고민해 보았지만 검색이나 갱신 둘 중 하나는 결국 비용이 발생한다 생각되었고, 가장 적합한 컬렉션으로 우선순위 큐를 선택해 코드2를 작성했다. 결과는 테스트 통과. 

 추가로 공부해 볼 것으로는 우선순위 큐가 offer나 poll로 갱신 될때 내부 정렬이 어떻게 되고, 비용이 얼마나 드는지 확인해 볼 필요가 있겠다.

 

 

코드2

import java.util.*;

class Solution {
    public int solution(int[] scoville, int K) {
        int answer;
        int count = 0;
        int temp1, temp2;
        
        PriorityQueue<Integer> que = new PriorityQueue<Integer>(scoville.length);
        for(int i : scoville) {
            que.offer(i);
        }
        
        while(que.size()>1) {
            if(que.peek()<K) {
                count++;
                temp1 = que.poll();
                que.offer(temp1+que.poll()*2);
                continue;
            }
            break;
        }
        
        if(que.peek()<K) {
            answer = -1;
        } else {
            answer = count;
        }
        
        return answer;
    }
}

 

 

코드1 (효율성 실패)

import java.util.*;

class Solution {
    public int solution(int[] scoville, int K) {
        int answer = 0;
        Arrays.sort(scoville);
        
        while(scoville.length>=2) {
            if(scoville[0]<K) {
                answer ++;
                scoville[1] = scoville[0]+scoville[1]*2;
                scoville = Arrays.copyOfRange(scoville,1,scoville.length);
                Arrays.sort(scoville);
            } else {
                break;
            }
        }
        
        if(scoville[0]<K) {
            answer = -1;
        }
        
        return answer;
    }
}

 

문제

온라인 저지에 가입한 사람들의 나이와 이름이 가입한 순서대로 주어진다. 이때, 회원들을 나이가 증가하는 순으로, 나이가 같으면 먼저 가입한 사람이 앞에 오는 순서로 정렬하는 프로그램을 작성하시오.

입력

첫째 줄에 온라인 저지 회원의 수 N이 주어진다. (1 ≤ N ≤ 100,000)

둘째 줄부터 N개의 줄에는 각 회원의 나이와 이름이 공백으로 구분되어 주어진다. 나이는 1보다 크거나 같으며, 200보다 작거나 같은 정수이고, 이름은 알파벳 대소문자로 이루어져 있고, 길이가 100보다 작거나 같은 문자열이다. 입력은 가입한 순서로 주어진다.

출력

첫째 줄부터 총 N개의 줄에 걸쳐 온라인 저지 회원을 나이 순, 나이가 같으면 가입한 순으로 한 줄에 한 명씩 나이와 이름을 공백으로 구분해 출력한다.

 

나의 풀이

 나이순, 이후에 가입순으로 정렬하기 위해 입력받는 값들로 객체를 만들어 주기로 했다. Info class를 만들고 나이와 이름을 저장하면서, 회원번호를 가입순으로 1씩 증가시키며 부여했다. compareTo 메서드를 먼저는 나이순, 나이가 같으면 가입순으로 정렬되게끔 구현하고, 생성한 Info 객체들을 list에 넣고 정렬 후 출력했다. Comparable 인터페이스를 구현하지 않고 Collections.sort()함수를 호출할때 비교기를 바로 넣어줘도 좋을 듯.

코드

import java.util.*;
import java.io.*;
class Info implements Comparable<Info> {
    static int counter;
    
    String name;
    int age;
    int number;
    
    public Info(int age,String name) {
        this.age = age;
        this.name = name;
        number = counter++;
    }
    
    @Override
    public int compareTo(Info i2) {
        if(this.age > i2.age) {
            return 1;
        } else if(this.age < i2.age) {
            return -1;
        } else {
            if(this.number>i2.number) {
                return 1;
            } else {
                return -1;
            }
        }
    }
    
    @Override
    public String toString() {
        return age+" "+name;
    }
}


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));
        int num = Integer.parseInt(br.readLine());
        StringTokenizer st;
        Info.counter = 0;
        
        List<Info> list = new ArrayList<>();
        for(int i=0; i<num; i++) {
            st = new StringTokenizer(br.readLine());
            int tempAge = Integer.parseInt(st.nextToken());
            String tempName = st.nextToken();
            list.add(new Info(tempAge, tempName));
        }
        
        Collections.sort(list);
        
        StringBuilder sb = new StringBuilder();
        for(int i=0; i<list.size(); i++) {
            sb.append(list.get(i).toString()).append("\n");
        }
        bw.write(sb.toString());
        
        bw.flush();
    }
}

+ Recent posts