[알고리즘] Programmers - 순위

2023. 9. 30. 15:39·알고리즘/programmers
 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

문제 설명

  • 선수의 수는 1명 이상 100명 이하이다.
  • 경기 결과는 1개 이상 4,500개 이하이다.
  • 경기 결과를 나타내는 리스트가 주어지는데, 이를 통해 순위를 정확하게 파악할 수 있는 선수들의 수를 반환해야 한다.
  • 모든 경기 결과에는 모순이 없다.

문제 해결

  • 승 여부를 확인할 수 있는 "승 그래프"와 패 여부를 확인할 수 있는 "패 그래프", 총 2개의 그래프를 구성했다.
  • 2개의 그래프를 dfs 탐색하며 자신보다 쎈 선수들과 약한 선수들을 파악한다.
  • dfs 탐색을 통해 방문할 수 없는 정점(선수)이 있는 경우 정확하게 파악할 수 없기 때문에 answer를 증가시키지 않는다.

시간 복잡도

  • O(N)

풀이 코드

import java.util.*;

class Solution {
    static List<List<Integer>> winGraph, loseGraph;
    static boolean[] v;
    
    public int solution(int n, int[][] results) {
        int answer = 0;
        
        winGraph = new ArrayList<>();
        loseGraph = new ArrayList<>();
        for (int i = 0; i <= n; i++) {
            winGraph.add(new ArrayList<>());
            loseGraph.add(new ArrayList<>());
        }
        
        for (int[] result : results) {
            int a = result[0];
            int b = result[1];
            winGraph.get(a).add(b);
            loseGraph.get(b).add(a);
        }
        
        for (int now = 1; now <= n; now++) {
            v = new boolean[n + 1];
            v[now] = true;
            dfs(now, winGraph);
            dfs(now, loseGraph);
            
            for (int i = 1; i <= n; i++) {
                if (!v[i]) break;
                if (i == n) {
                    answer++;
                }
            }
        }
        
        return answer;
    }
    
    static void dfs(int now, List<List<Integer>> graph) {
        for (int next : graph.get(now)) {
            if (v[next]) continue;
            v[next] = true;
            dfs(next, graph);
        }
    }
    
}

결과


1차 시도

1. 풀이 코드

import java.util.*;

class Solution {
    static List<List<Integer>> winGraph, loseGraph;
    static boolean[] v;
    
    public int solution(int n, int[][] results) {
        int answer = 0;
        
        winGraph = new ArrayList<>();
        loseGraph = new ArrayList<>();
        for (int i = 0; i <= n; i++) {
            winGraph.add(new ArrayList<>());
            loseGraph.add(new ArrayList<>());
        }
        
        for (int[] result : results) {
            int a = result[0];
            int b = result[1];
            winGraph.get(a).add(b);
            loseGraph.get(b).add(a);
        }
        
        for (int now = 1; now <= n; now++) {
            v = new boolean[n + 1];
            v[now] = true;
            dfs(now, winGraph);
            dfs(now, loseGraph);
            
            for (int i = 1; i <= n; i++) {
                if (!v[i]) break;
                if (i == n) {
                    answer++;
                }
            }
        }
        
        return answer;
    }
    
    static void dfs(int now, List<List<Integer>> graph) {
        for (int next : graph.get(now)) {
            if (v[next]) continue;
            v[next] = true;
            dfs(next, graph);
        }
    }
    
}

2. 문제점

  • 승 그래프, 패 그래프 총 2개의 그래프를 탐색하는 2번의 dfs로 인해 시간 복잡도가 증가하는 문제점이 발생했다.
  • 두 개의 그래프를 그리기 때문에 메모리 측면에서도 공간을 더 차지하는 문제점이 있다.

3. 결과


2차 시도

1. 풀이코드

import java.util.*;

class Solution {
    public int solution(int n, int[][] results) {
        int answer = n;
        int INF = n * n;
        int[][] graph = new int[n + 1][n + 1];
        
        for (int i = 1; i <= n; i++) {
            Arrays.fill(graph[i], INF);
            graph[i][i] = 0;
        }
        
        for (int[] result : results) {
            int a = result[0];
            int b = result[1];
            graph[a][b] = 1;
        }
        
        for (int k = 1; k <= n; k++) {
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    graph[i][j] = Math.min(graph[i][j], graph[i][k] + graph[k][j]);
                }
            }
        }
        
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (i == j) continue;
                
                if (graph[i][j] == INF && graph[j][i] == INF) {
                    answer--;
                    break;
                }
            }
        }
        
        return answer;
    }
}

2. 1차 시도 코드 개선점

  • 플로이드 와샬 알고리즘을 적용하여 모든 정점을 탐색할 수 있는지 확인하는 로직으로 구성했다.
  • 1차 시도 방법과 비교했을 때, 시간과 메모리 측면에서 1차 시도 방법이 더 효율적인 것을 볼 수 있다.
  • 플로이드 와샬 방법보다는 dfs를 2번 수행하는 방식이 더 효율적이다.

3. 결과

'알고리즘 > programmers' 카테고리의 다른 글

[알고리즘] Programmers - 124 나라의 숫자  (0) 2023.09.25
[알고리즘] Programmers - 풍선 터트리기  (0) 2023.08.28
[알고리즘] Programmers - 리코쳇 로봇  (1) 2023.08.28
'알고리즘/programmers' 카테고리의 다른 글
  • [알고리즘] Programmers - 124 나라의 숫자
  • [알고리즘] Programmers - 풍선 터트리기
  • [알고리즘] Programmers - 리코쳇 로봇
tableMinPark
tableMinPark
Backend Engineer
  • tableMinPark
    Sangmin's Tech Blog
    tableMinPark
  • 전체
    오늘
    어제
  • 블로그 메뉴

    • tech study blog
    • my github
    • monglife github
    • 분류 전체보기 (48)
      • 개발 (7)
        • java (0)
        • kotlin (0)
        • spring boot (0)
        • android (0)
        • junit5 (5)
        • architecture (2)
      • 데브옵스 (3)
        • docker (3)
        • github action (0)
        • grafana (0)
        • prometheus (0)
        • elk (0)
      • 알고리즘 (35)
        • baek joon (0)
        • programmers (4)
        • leet code (29)
      • 일상 (3)
        • Wear OS 앱 개발기 (2)
        • 회고 (1)
  • 태그

    jetpack-compose
    wear os
    volume
    Container
    micro service
    monglife
    Thread
    20.04
    MSA
    java
    mongs
    MVVM
    bind mount
    docker
    docker network
    layered architecture
    Android
    Galaxy watch
    Kotlin
    apple watch
    레이어드 아키텍처
    ubuntu
    docker-compose
    synchronized
    docker compose
  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
tableMinPark
[알고리즘] Programmers - 순위
상단으로

티스토리툴바