특정 강의를 듣기 위해서 다른 강의를 들어야 하는 정보가 주어질 때 정상적으로 강의를 들을 수 있는 지에 대한 문제이다. 강의의 관계가 순환 참조 되는 경우 불가능하다고 판단해야 한다.

 

처음에는 dfs 백트래킹 방식으로 해결하려 하였으나 시간 초과가 되었다. 알고리즘을 바꿔야 하나 고민도 했지만 같은 관계를 여러 번 반복해서 검사를 수행하는 경우가 생긴다는 문제를 알게 되었다. 동일 경로에 대해 어떻게 처리할까 고민하던 중 일반적인 visited를 boolean으로 사용하는 방식 대신 int를 이용하여 미방문,방문,경로완료의 형태로 세가지 상태로 visited 배열을 관리하여 해결해 보았다. 결과적으로 시간 초과의 문제를 해결하고 통과할 수 있었다.

import java.util.*;  
  
public class Solution {  
  
    static int VISITED = 1;  
    static int COMPLETE = 2;  
  
    public boolean canFinish(int numCourses, int[][] prerequisites) {  
        List<Integer>[] preCourse = new ArrayList[numCourses];  
        for(int i = 0; i < numCourses; i++){  
            preCourse[i] = new ArrayList<Integer>();  
        }  
  
        for(int[] info : prerequisites){  
            int course = info[0];  
            int need = info[1];  
  
            preCourse[course].add(need);  
        }  
  
        int[] visited = new int[numCourses];  
        for(int i = 0; i < numCourses; i++){  
            if(preCourse[i].isEmpty()) continue;  
            if(!isPossible(i, preCourse, visited)){  
                return false;  
            }  
        }  
  
        return true;  
    }  
  
    private boolean isPossible(int course, List<Integer>[] preCourse, int[] visited){  
  
        if(visited[course] == COMPLETE){  
            return true;  
        }  
  
        if(visited[course] == VISITED){  
            return false;  
        }  
  
        visited[course] = VISITED;  
  
        for(int pre: preCourse[course]){  
            if(!isPossible(pre, preCourse, visited)){  
                return false;  
            };  
        }  
  
        visited[course] = COMPLETE;  
        return true;  
    }  
  
}

'Algolithm-Leetcode > Graphs' 카테고리의 다른 글

Word Ladder  (0) 2026.08.27
Pacific Atlantic Water Flow  (0) 2026.08.16
Clone Graph  (0) 2026.08.12
Number of Islands  (0) 2026.07.31

https://leetcode.com/problems/word-search/description/

 

Word Search - LeetCode

Can you solve this real interview question? Word Search - Given an m x n grid of characters board and a string word, return true if word exists in the grid. The word can be constructed from letters of sequentially adjacent cells, where adjacent cells are h

leetcode.com

 

주어진 보드의 문자를 연결해서 타겟으로 하는 문자열이 존재하는지 체크하는 문제이다.
기본적인 DFS 백트래킹으로 문제를 풀 수 있다. 보드의 상하좌우 탐색, 방문 체크, 조건 체크와 boolean 값 리턴 등에서 오류가 나지 않게 처리해주면 무난히 풀 수 있었다. 최종 코드는 아래와 같다.

public class Solution {  
  
    int[] dr = {1, 0, -1, 0};  
    int[] dc = {0, 1, 0, -1};  
    boolean[][] visited;  
  
    public boolean exist(char[][] board, String word) {  
        int m = board.length;  
        int n = board[0].length;  
        visited = new boolean[m][n];  
  
        for(int i = 0; i < m; i++){  
            for(int j = 0; j < n; j++){  
                if(board[i][j] == word.charAt(0)){  
                    visited[i][j] = true;  
                    if(dfs(board, i, j, 0, word)){  
                        return true;  
                    };  
                    visited[i][j] = false;  
                }  
            }  
        }  
  
        return false;  
    }  
  
    private boolean dfs(char[][] board, int r, int c, int idx, String word){  
        if(idx == word.length() - 1){  
            return true;  
        }  
  
        if(idx > word.length() - 1){  
            return false;  
        }  
  
        int nextIdx = idx + 1;  
        for(int dir = 0; dir < 4; dir++){  
            int nextRow = r + dr[dir];  
            int nextCol = c + dc[dir];  
            if(nextRow >= 0 && nextRow < board.length  
                    && nextCol >= 0 && nextCol < board[0].length  
                    && !visited[nextRow][nextCol]  
                    && board[nextRow][nextCol] == word.charAt(nextIdx)  
            ){  
                visited[nextRow][nextCol] = true;  
                if(dfs(board, nextRow, nextCol, nextIdx, word)){  
                    return true;  
                };  
                visited[nextRow][nextCol] = false;  
            }  
        }  
  
        return false;  
    }  
}

 

같은 형태로 문자열 배열을 체크하는 문제가 있었는데 해당 문제는 상당히 어려웠었다. 이 문제를 해결한 이후 Trie 자료구조 알고리즘을 공부했다면 도전할 만 하다.

 

https://ygs3004.tistory.com/93

 

Word Search II

https://leetcode.com/problems/word-search-ii/description/ Word Search II - LeetCodeCan you solve this real interview question? Word Search II - Given an m x n board of characters and a list of strings words, return all words on the board. Each word must be

blog.honey-sleep.co.kr

'Algolithm-Leetcode > Backtracking' 카테고리의 다른 글

N-Queens  (0) 2026.08.26
Permutations  (0) 2026.08.16
Combination Sum  (0) 2026.08.10
Subsets  (0) 2026.07.31

https://leetcode.com/problems/subsets/description/

 

Subsets - LeetCode

Can you solve this real interview question? Subsets - Given an integer array nums of unique elements, return all possible subsets (the power set). The solution set must not contain duplicate subsets. Return the solution in any order.   Example 1: Input: n

leetcode.com

 

주어진 배열의 모든 subset을 List로 리턴하는 문제이다.
각 요소를 순회하기 위하여 dfs로 백트래킹을 하여 가능하며, 중복 요소를 제거하기 위하여
현재 인덱스 이후 기준으로 dfs 탐색 하였다.

import java.util.*;  
  
public class Solution {  
    public List<List<Integer>> subsets(int[] nums) {  
        List<List<Integer>> answer = new ArrayList<>();  
        List<Integer> cur = new ArrayList<>();  
        boolean[] visited = new boolean[nums.length];  
        dfs(answer, cur, -1, visited, nums);  
  
        return answer;  
    }  
  
    private void dfs(List<List<Integer>> answer, List<Integer> cur, int curidx, boolean[] visited, int[] nums){  
        // Array 의 값을 복사하여 넣어준다.  
        List<Integer> subset = new ArrayList<>(cur);  
        answer.add(subset);  
  
        for(int i = curidx + 1; i < visited.length; i++){  
            if(!visited[i]){  
                cur.add(nums[i]);  
                int curSize = cur.size();  
                visited[i] = true;  
                dfs(answer, cur, i, visited, nums);  
                // 값을 다시 초기화하여 백트래킹 한다.  
                visited[i] = false;  
                cur.remove(curSize - 1);  
            }  
        }  
    }  
}

 

서브 셋을 추가할 땐 해당 배열을 복사해서 추가해주었다.

List의 참조 값을 바라보므로 해당 시점의 배열 요소로 복사해서 넣어주어야 한다.

'Algolithm-Leetcode > Backtracking' 카테고리의 다른 글

N-Queens  (0) 2026.08.26
Word Search  (0) 2026.08.22
Permutations  (0) 2026.08.16
Combination Sum  (0) 2026.08.10

코딩테스트 문제를 풀 다 시간 초과를 해결했던 경험에 대한 기록이다.

백준의 텀프로젝트 문제를 풀던 중(https://www.acmicpc.net/problem/9466)
내가 작성한 코드가 충분히 최적화 되었다고 생각했음에도 계속 시간 초과가 발생하였다.
관련하여 문제를 찾던 중 자바의 배열 생성이 시간 초과의 원인이 될 수 있다는 글을 발견하고, 해당 부분을 수정하여 통과하였다.


    private static int solution() throws IOException {
        int studentNum = Integer.parseInt(br.readLine());
        int[] team = new int[studentNum + 1];
        String[] input = br.readLine().split(" ");
        for(int i = 1; i <= studentNum; i++){
            team[i] = Integer.parseInt(input[i-1]);
        }

        checked = new boolean[studentNum + 1];
        result = studentNum;

        for(int i = 1; i <= studentNum; i++){
            if(checked[i]) continue;
            // 배열 초기화
            visited = new int[studentNum + 1];
            findTeam(team, i, 1, visited);
        }

        return result;
    }

    private static void findTeam(int[] team, int student, int seq, int[] visited){
        if(checked[student]) return;
        checked[student] = true;
        visited[student] = seq;

        int next = team[student];
        if(visited[next] != 0){
            result -= (seq - visited[next] + 1);
        }else{
            findTeam(team, next, seq + 1, visited);
        }
    }

 

시간 초과가 나던 시점의 내 코드는 위와 같았으며, 완전 탐색을 위하여 탐색 방문 배열을 new 명령어로 생성하고 있었다. 해당 배열의 크기는 최대 100001의 크기를 갖는 문제이다.

 

    private static int solution() throws IOException {
        int studentNum = Integer.parseInt(br.readLine());
        int[] team = new int[studentNum + 1];
        StringTokenizer st = new StringTokenizer(br.readLine());
        for(int i = 1; i <= studentNum; i++){
            team[i] = Integer.parseInt(st.nextToken());
        }

        checked = new boolean[studentNum + 1];
        int[] visited = new int[studentNum + 1];
        result = studentNum;
        for(int i = 1; i <= studentNum; i++){
            if(checked[i]) continue;
            findTeam(team, i, 0, visited);
        }

        return result;
    }

    private static void findTeam(int[] team, int student, int seq, int[] visited){
        if(checked[student]) return;
        seq++;
        checked[student] = true;
        visited[student] = seq;

        int next = team[student];
        if(visited[next] != 0){
            result -= (seq - visited[next] + 1);
        }else{
            findTeam(team, next, seq, visited);
        }

        // dfs 내부에서 사용후 값 원상복구
        visited[student] = 0;
    }

}

 

시간 초과를 해결한 코드는 위와 같다. dfs를 반복하기 이전에 생성한 배열의 값을 new 가 아닌 직접 초기화 하여 배열을 사용하였다. 참고한 글(https://okky.kr/questions/1450047)에 따르면 배열을 생성한다는 것은 새로운 객체의 메모리에 할당 받는 부분, java의 경우 해당 배열의 초기 값을 초기화하는 부분 등으로 인하여 런타임 실행 시간이 늘어날 수 있다고 한다. 단순한 코드의 차이였지만 객체 생성의 효율에 대해 고민할 수 있었다.

+ Recent posts