코딩테스트/Java

(2018카카오) 후보키 Java

SK_MOUSE 2021. 1. 14. 15:43
반응형

https://programmers.co.kr/learn/courses/30/lessons/42890

 

일반적인 탐색문제이다..DFS방식도 있지만 완전탐색이 더 실행속도 측면에서 빨랐다.

 

하지만 Bit Mask방식으로 For문으로 경우의수를 나눠서 풀 수 있다.

BitMask방식은 이진법을 이용하여 0=000(2) ~ 15=111(2) 으로 001, 010, 011, ... , 110, 111 방식으로 

 

https://keepgoing0328.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-2019-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EA%B3%B5%EC%B1%84-%ED%9B%84%EB%B3%B4%ED%82%A4-%EC%9E%90%EB%B0%94-bitmask

 

[ 프로그래머스 - 2019 카카오 공채 ] 후보키 ( 자바, bitmask )

[ 프로그래머스 - 2019 카카오 공채 ] 후보키 bitmask ( java, bitmask ) 프렌즈대학교 컴퓨터공학과 조교인 제이지는 네오 학과장님의 지시로, 학생들의 인적사항을 정리하는 업무를 담당하게 

keepgoing0328.tistory.com

 

아래는 완전탐색 풀이다. 문자열을 비교할때 콤마를 넣어주는것이 원칙적으로 올바른 비교다.

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;


class Solution {
    public int solution(String[][] relation) {
        int n = relation.length;        // n개의 데이터
        int m = relation[0].length;     // m개의 컬럼
        ArrayList<Integer> list = new ArrayList<Integer>();

        // 완전 탐색을 돈다.
        for(int i=1; i<(1<<m); i++) {
            Set<String> s = new HashSet<String>();
            // n개의 데이터
            for(int j=0; j<n; j++) {
                String now = "";
                // m개의 컬럼
                for(int k=0; k<m; k++) {
                    // 모든 경우의 수 & 해당 라인 데이터 조합.
                    if( (i&(1<<k)) > 0 ) {
                        now+="," + relation[j][k];
                    }
                }
                s.add(now);
            }
            if(s.size()==n&&possi(list,i)) list.add(i);
        }
        //System.out.println(list.size());
        return list.size();
    }
    public static boolean possi(ArrayList<Integer> list, int now) {
        for(int i=0; i<list.size(); i++) {
            // 같으면 최소성을 만족하지 못함.
            if((list.get(i)&now)==list.get(i)) {
                return false;
            }
        }
        return true;
    }
}

 

dfs방식이다.

import java.util.*;

class Solution {
    public int solution(String[][] relation) {
        candidates = new ArrayList<HashSet<Integer>>();

        select(0, new HashSet<Integer>(), relation);
        return candidates.size();
    }

    static ArrayList<HashSet<Integer>> candidates;

    // select() : column에 대한 모든 부분 집합을 만든다. 하나의 부분 집합(selects)이 만들어지면, 후보키인지 검사 후 candidates에 추가한다.
    // column에서 pos 번째 열, selects: dfs에서 만들어지는 부분 집합
    static void select(int pos, HashSet<Integer> selects, String[][] relation) {

        if (pos == relation[0].length) {

            // 만들어진 selects가 다른 후보키를 포함하나
            for (int i = 0; i < candidates.size(); i++) {
                if (selects.containsAll(candidates.get(i))) {
                    return;
                }
            }

            // selects가 유일성을 만족하나
            HashSet<String> sets = new HashSet<String>();
            for (int row = 0; row < relation.length; row++) {
                String temp = "";
                for (int col : selects) {
                    temp += relation[row][col] + ",";
                }
                if (sets.contains(temp)) {
                    return;
                }
                sets.add(temp);
            }

            // 추가!
            candidates.add(selects);
            return;
        }

        // call by value 이기 때문에 copy, copy2
        HashSet<Integer> copy = new HashSet<Integer>();
        HashSet<Integer> copy2 = new HashSet<Integer>();
        for (Integer val : selects) {
            copy.add(val);
            copy2.add(val);
        }

        select(pos + 1, copy2, relation);
        copy.add(pos);
        select(pos + 1, copy, relation);


    }
}

 

반응형