완전탐색

프로그래머스 레벨2 피로도 문제이다.

이 문제를 풀면서 dfs의 동작 방식에 대해 좀 더 잘 이해할 수 있었던것 같다.

 

풀이

  1. 각 던전의 인덱스에 해당하는 방문 기록 visited를 만든다.
  2. for 문을 돌려서 인덱스에 해당하는 던전에 방문하지 않았고, 입장 시 필요한 피로도를 충족한 경우를 찾는다.
  3. 방문 기록을 남기고 다음 depth로 깊이 우선 탐색을 실행한다.
  4. for 문의 다음 루프에 영향이 가지 않도록 visited 를 초기화 한다.
  5. 재귀함수를 돌아서 가장 깊은 depth 까지 탐색을 한 경우의 depth를 기록한다.

최종 코드

import java.util.*;
class Solution {
    static int answer = 0;
    static boolean[] visited;
    
    public void dfs(int[][] dungeons, int left, int depth) {
    	// 2. for 문을 돌려서 인덱스에 해당하는 던전에 방문하지 않았고, 
        // 입장 시 필요한 피로도를 충족한 경우를 찾는다.
        for (int i = 0; i < dungeons.length; i++) {
            if (visited[i] == false && left >= dungeons[i][0]) {
            	// 3. 방문 기록을 남기고 다음 depth로 깊이 우선 탐색을 실행한다.
                visited[i] = true;
                dfs(dungeons, left - dungeons[i][1], depth +1);
                // 4. for 문의 다음 루프에 영향이 가지 않도록 visited 를 초기화 한다.
                visited[i] = false;
            }
        }
        // 5. 재귀함수를 돌아서 가장 깊은 depth 까지 탐색을 한 경우의 depth를 기록한다.
        answer = Math.max(answer, depth);
    }
    public int solution(int k, int[][] dungeons) {
    	// 1. 각 던전의 인덱스에 해당하는 방문 기록 visited를 만든다.
        visited = new boolean[dungeons.length];
        int left = k;
        dfs(dungeons, left, 0);
        return answer;
    }
}

'알고리즘 > 완전탐색' 카테고리의 다른 글

[알고리즘] 소수찾기  (0) 2023.11.12

BFS

프로그래머스 레벨2의 단어 변환 문제이다.

이 문제는 가장 짧은 변환 과정을 찾아야하고 bfs 는 최단거리를 보장해주는 알고리즘이므로 bfs 를 사용해야한다.

좀 더 공부해봐야 알겠지만 dfs 는 최단 거리가 보장이 안될 수도 있지 않을까?

bfs 문제를 많이 풀어보지는 않아서 정확히는 모르겠지만 전에 푼 문제처럼 Queue 를 이용한다.

 

풀이

  1. 너비 우선 탐색 알고리즘을 이용하여 탐색한다.
  2. 큐에서 idx, move 의 초기값(0, 0)을 꺼내서 visited 에 방문 여부 겸 이동 수를 기록
  3. 탐색 조건에 의해 변환할 수 없는 경우의 수는 걸러지고 남은 경우들은 각자의 최선의 선택으로 탐색
  4. 탐색 후  다음 좌표를 큐에 저장하고 다음 좌표의 방문 여부 겸 이동 수를  visited 에 기록
  5. 각자의 최선의 선택으로 탐색한 경우만 남았으므로 최단 변환 과정은 bfs의 값을 인덱스로 하는 visited 의 값
  6. 큐가 비어서 탐색을 진행할 수 없는 경우 bfs 메서드는 0을 반환
  7. 탐색 종료 후 bfs 의 결과 값을 인덱스로 하는 visited 의 값을 반환(0 이면 변환 불가라는 뜻이므로 0)

최종 코드

import java.util.*;
class Solution {
    // 너비 우선 탐색
    public int bfs(String[] new_words, int[] visited, String target) {
        Queue<int[]> que = new LinkedList<>();
        // 초기값 (idx, move) = (0, 0)
        que.add(new int[2]);
        
        // que 에서 idx 와 move 를 꺼내서 사용하며
        // que 가 비었다는건 words 를 모두 방문했다는 뜻이므로 변환 불가라는 뜻
        while(!que.isEmpty()) {
            int[] now = que.poll();
            int idx = now[0];
            int move = now[1];
            
            // 탐색 조건
            // 1. 방문하지 않은 words
            // 2. 바뀐 글자가 1개
            for (int i = 1; i < new_words.length; i++) {
                int diff = 0;
                // 바뀐 글자가 1개 뿐인지 체크
                for (int j = 0; j < new_words[i].length(); j++) {
                    if (new_words[idx].charAt(j) != new_words[i].charAt(j)){
                        diff += 1;
                    }
                }
                if (visited[i] == 0 && diff == 1) {
                	// 조건에 맞을 경우 이동수 +1
                    // visitied[i] 에 이동수 기록
                    move += 1;
                    visited[i] = visited[idx] +1;
                    // target 으로 변환 시 해당 visited의 인덱스 i 반환
                    if (new_words[i].equals(target)) {
                        return i;
                    }
                    que.add(new int[]{i, move});
                }
            }
        }
        return 0;
    }
    public int solution(String begin, String target, String[] words) {
        String[] new_words = new String[words.length +1];
        new_words[0] = begin;
        for (int i = 0; i < words.length; i++) {
            new_words[i +1] = words[i];
        }
        int[] visited = new int[new_words.length];
        int result = bfs(new_words, visited, target);
        
        // result = 도착점의 visited 인덱스
        // result 가 0 이면 변환 불가라는 의미
        // result 가 0 이 아니면 visited[result] 가 이동수
        return result == 0 ? 0 : visited[result] ;
    }
}

'알고리즘 > DFS 및 BFS' 카테고리의 다른 글

[알고리즘] BFS 입문(JAVA)  (0) 2023.10.22
[알고리즘] DFS 입문(JAVA)  (0) 2023.10.15

완전탐색

프로그래머스 레벨2 소수 찾기 문제이다.

완전탐색은 dfs 와 비슷한 방식인듯 싶기도 한데, 익숙해지려면 좀 더 많은 문제를 풀어봐야 겠다.

 

풀이

  1. 재귀 함수를 통해 완전 탐색하여 만들 수 있는 모든 숫자를 int 로 변환한다.
  2. 각 숫자를 소수 판별하여 소수일 경우 set 에 추가한다. (각 숫자의 제곱근까지만 약수의 여부 검증)
  3. set 의 사이즈가 이 문제의 답

최종 코드

import java.util.*;
class Solution {
    Set<Integer> set = new HashSet<>();
    
    // 소수 판별 메서드
    public boolean isPrime(int item) {
        if (item <= 1) {
            return false;
        }
        int limit = (int) Math.sqrt(item);
        for (int i = 2; i <= limit; i++) {
            if (item % i == 0) {
                return false;
            }
        }
        return true;
    }
    
    // 재귀 함수
    public void reculsive(String start, String rest) {
        if (!start.equals("")) {
            int item = Integer.parseInt(start);
            // 소수 판별
            if (isPrime(item)) {
                set.add(item);
            }
        }
        for (int i = 0; i < rest.length(); i++) {
            reculsive(start + rest.charAt(i), 
                rest.substring(0, i) + rest.substring(i+1));
        }
    }
    
    public int solution(String numbers) {
        reculsive("", numbers);
        return set.size();
    }
}

'알고리즘 > 완전탐색' 카테고리의 다른 글

[알고리즘] 피로도  (0) 2023.11.16

정렬

프로그래머스 레벨2의 가장 큰 수에서 comparator 를 처음 써보았다.

처음 보는거라 그런지 comparator 라는걸 이해하는게 힘들었다. 문제들을 더 풀어보면서 익숙해지는 수 밖에 없을듯.

문제 자체는 이 comparator 를 사용하는법만 알면 풀리긴 했다.

 

Comparator

/** Arrays.sort(arr, (o1, o2) -> o1.compareTo(o2))
 *  arr 는 String 배열
 *  o1, o2 는 String 값
 *  o1, o2 에 대하여 o1 > o2 이면 o1, o2 순서를 바꾼다.
 *  o1, o2 에 대하여 o1 = o2 이면 그대로.
 *  o1, o2 에 대하여 o1 < o2 이면 그대로.
 */
Arrays.sort(arr, (o1, o2) -> o1.compareTo(o2))   // 오름차순
Arrays.sort(arr, (o1, o2) -> o2.compareTo(o1))   // 내림차순

위와 같이 stream 으로 compare 을 오버라이드 할 수도 있나보다.

 

풀이

  1. int 배열을 String 배열로 바꾼다.
  2. comparator 를 이용하여 Arrays.sort() 메서드로 조건에 맞춰 정렬한다. (숫자 조합 시 큰 경우가 되도록)
  3. 예외 조건을 추가한다. (String 배열에서 0번째 수가 0인 경우는 배열 원소 모두 "0" 인 경우이므로 "0"을 반환)

최종 코드

import java.util.*;
class Solution {
    public String solution(int[] numbers) {
        String[] arr = new String[numbers.length];
        StringBuilder answer = new StringBuilder();
        
        // int 배열을 String 배열로 변환
        for (int i = 0; i < numbers.length; i++) {
            arr[i] = String.valueOf(numbers[i]);
        }
        
        // Comparator를 이용
        Arrays.sort(arr, (o1, o2) -> (o2 + o1).compareTo(o1 + o2));
        
        // 예외 조건 추가
        if (arr[0].equals("0")) {
            return "0";
        }
        
        // 예외 조건이 아닐 시 정렬된 배열을 순서대로 합친 문자열을 반환
        for (String a : arr) {
            answer.append(a);
        }
        return answer.toString();
    }
}

BFS

프로그래머스 게임 맵 최단거리 문제를 통해 처음 bfs 를 접해보았다. 

bfs 가 무엇인가 맛보고 이해하기에 좋은 문제인것 같다.

dfs 로 풀어보려고 안간 힘을 써봤지만 실패했다. 

최단거리 문제는 대표적인 bfs 문제라고 하며, Queue 를 이용한다.

 


풀이

  1. 너비 우선 탐색 알고리즘을 이용하여 탐색
  2. queue 에서 시작 좌표 값(0, 0)을 꺼내서 visited 에 방문 여부 겸 이동 수를 기록 후 사방탐색 시작
  3. 사방탐색 조건에 의해 사방이 막혔거나 방문한 길 밖에 없는 경우의 수는 걸러지고 남은 경우들은 각자의 최선의 선택으로 탐색
  4. 사방탐색 후 다음 좌표를 queue 에 저장하고 다음 좌표의 방문 여부 겸 이동 수를  visited 에 기록
  5. 각자의 최선의 선택으로 탐색한 경우만 남았으므로 가장 먼저 queue 가 비어서 탐색을 진행할 수 없는 경우가 최단거리
  6. 탐색 종료 후 도착점 좌표에 해당하는 visited 의 값을 반환(0 이면 방문한 적이 없다는 뜻이므로 -1)

최종 코드

import java.util.*;
class Solution {
    int n = 0;
    int m = 0;
    // 사방탐색용 dx, dy
    int[] dx = {1, 0, -1, 0};
    int[] dy = {0, 1, 0, -1};

	// 너비 우선 탐색
    public void bfs(int[][] maps, int[][] visited, int x, int y) {
    	// 방문 여부 겸 이동 수를 해당 시작 좌표에 기록
        visited[y][x] = 1;
        // queue 초기값 (0, 0)
        Queue<int[]> que = new LinkedList<>();
        que.add(new int[]{y, x});
        
        // queue 에서 현재 좌표를 꺼내서 사용
        // queue 가 비었다는건 더 이상 탐색할 수 없다는 뜻
        while (!que.isEmpty()) {
            int[] now = que.poll();
            y = now[0];
            x = now[1];
			
            // 사방탐색 조건
            // 1. y, x 가 최대값(n, m)을 넘지 않음
            // 2. 방문하지 않은 좌표(visited = 0 인 좌표)
            // 3. 해당하는 maps 의 값이 1인 좌표
            for (int i = 0; i < 4; i++) {
                if (x + dx[i] >= 0 &&
                   x + dx[i] < m &&
                   y + dy[i] >= 0 &&
                   y + dy[i] < n &&
                   visited[y + dy[i]][x + dx[i]] == 0 &&
                   maps[y + dy[i]][x + dx[i]] == 1) {
                    // 탐색 조건에 만족할 시 다음 좌표에 방문 여부 겸 이동 수를 기록
                    visited[y + dy[i]][x + dx[i]] = visited[y][x] + 1;
                    // 다음 좌표를 queue 에 추가
                    que.add(new int[]{y + dy[i], x + dx[i]});
                }
            }
        }
    }

    public int solution(int[][] maps) {
        n = maps.length;
        m = maps[0].length;
        int[][] visited = new int[n][m];
        // 너비 우선 탐색 시작
        // 초기값 (0, 0) 설정
        bfs(maps, visited, 0, 0);

        // 도착점(visited) 의 값을 확인
        // 0 이면 방문한 적이 없으므로 -1
        // 0 이 아니면 visited 의 해당 값이 이동 수를 의미
        return visited[n -1][m -1] == 0 ? -1 : visited[n -1][m -1];
    }
}

'알고리즘 > DFS 및 BFS' 카테고리의 다른 글

[알고리즘] 단어 변환(JAVA)  (0) 2023.11.14
[알고리즘] DFS 입문(JAVA)  (0) 2023.10.15

레벨1 완주

처음엔 하루종일 코테만 해서 빨리 풀었지만 슬슬 다른거랑 병행하다보니 생각보다 되게 오래 걸렸다.

스프링 공부, 네트워크 공부, 배운거 정리하느라 시간이 모자라서 하루에 2문제 푸는게 목표가 되었다.

레벨1도 어렵긴 하지만 레벨1만 풀면 실력이 늘지 않는 느낌이라 레벨2~3이나 리트코드 문제도 같이 풀었다.

레벨0은 기본기였다면 레벨1은 레벨0에서 배운 기본기를 조합해서 푸는 느낌이었다.

 

앞으로의 목표

아직 bfs, dfs, 이분탐색 정도만 개념을 알지 다른건 잘 모르겠으니 카테고리별로 개념 정리부터 해봐야겠다. 

이제부터는 다양한 카테고리의 문제들도 풀어보고 자료구조도 한번씩 구현해보면서 그놈의 트리가 뭔지 알아볼것이다.

겨우 걸음마를 뗀 초보에 불과하지만 다른 공부랑 병행하면서 꾸준히 하루 2문제씩 풀고 복습하다보면 꾸준히 늘겠지.

한 달 전에는 0레벨도 힘들었다. 이제 레벨1까지는 그럭저럭 풀 수 있고 분명 한 달 전보다는 보는 눈이 트인것 같다.

한 달 뒤에는 모든 문제 유형 정도는 구분하고 풀 수 있을 정도가 되도록 노력해보자.

이분탐색

이분탐색 자체는 리트코드 35.Search Insert Position을 통해서 처음 접했고,

프로그래머스에서는 입국심사를 통해 처음 접했다.

리트코드 문제에서 이분탐색이라는 개념을 이해했고 프로그래머스 문제에서 사고를 확장하는데 도움이 됐다.

 


풀이

프로그래머스 입국심사 문제 풀이

 

  1. times 배열을 오름차순으로 정렬한다.
  2. 최소시간 min은 최단 수행시간인 times[0] 만에 모든 입국심사가 끝났을때이다.
  3. 최대시간 max는 최장 수행시간인 times[times.length] 로 n명을 입국심사 한 값이다.
  4. min 과 max 사이에서 이분탐색을 수행한다.
  5. 중간값 mid 의 시간동안 각각의 심사관이 처리할 수 있는 인원 수 sum을 각각 더한다.
  6. sum == n 이 되는 mid의 최소값을 구한다.

최종 코드

import java.util.*;
class ImmigrationInspection {
    public long solution(int n, int[] times) {
    	// times 를 오름차순으로 정렬
        Arrays.sort(times);
        long answer = 0;
        
        // 최소값, 최대값 설정
        long min = (long)times[0];
        long max = (long)times[times.length -1] * n;
        long mid = 0;
        
        // 이분탐색 수행
        while (min <= max) {
            long sum = 0;
            mid = (min + max) /2;
            
            // 중간값 mid 의 시간동안 각각의 심사관이 처리할 수 있는 인원 수
            for (int time : times) {
                sum += mid / time;
            }
            
            // sum == n 을 만족하는 mid 의 최소값을 구한다.
            if (sum >= n) {
                answer = mid;
                max = mid -1;
            } else {
                min = mid +1;
            }
        }
        return answer;
    }
}

DFS

프로그래머스 타겟 넘버 문제를 통해 처음 dfs 를 접해보았다. 

dfs 가 무엇인가 맛보고 이해하기에 좋은 문제인것 같다.

 


풀이

  1. 깊이 우선 탐색 알고리즘을 이용하여 탐색을 시작한다.
  2. 처음 노드(depth = 0)부터 마지막 노드(depth = numbers.length)까지 탐색을 수행
  3. 마지막 노드까지 탐색했을 때 타겟 넘버와 결과값이 같으면 정답 카운트 1 증가

깊이 우선 탐색 알고리즘

public void dfs(int[] numbers, int depth, int target, int sum) {
    // numbers : 알고리즘을 수행할 대상 배열
    // depth : 노드의 깊이
    // target : 타겟 넘버
    // sum : 이전 노드까지의 결과값
}

 

최종 코드

public class TargetNumber {
    // 정답 카운트
    // 초기값 0부터 시작
    int answer = 0;

    // 깊이 우선 탐색
    public void dfs(int[] numbers, int depth, int target, int sum) {
        // 마지막 노드까지 탐색했을 때 sum == target 이면 정답 카운트 1 증가
        if (depth == numbers.length) {
            answer += sum == target ? 1 : 0;
        } else {
            // depth 가 0 부터 numbers.length 까지 numbers[depth] 값을 +, - 를 동시에 진행한다.
            dfs(numbers, depth +1, target, sum + numbers[depth]);
            dfs(numbers, depth +1, target, sum - numbers[depth]);
        }
    }

    public int solution(int[] numbers, int target) {
        // 깊이 우선 탐색 시작
        // depth 초기값은 0
        dfs(numbers, 0, target, 0);
        return answer;
    }
}

 


참고자료)

 

[프로그래머스] 타겟 넘버 - Java

https://programmers.co.kr/learn/courses/30/lessons/43165 코딩테스트 연습 - 타겟 넘버 n개의 음이 아닌 정수가 있습니다. 이 수를 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다. 예를 들어 [1, 1, 1, 1, 1]로

hyojun.tistory.com

 

'알고리즘 > DFS 및 BFS' 카테고리의 다른 글

[알고리즘] 단어 변환(JAVA)  (0) 2023.11.14
[알고리즘] BFS 입문(JAVA)  (0) 2023.10.22

+ Recent posts