programmers. 숫자 야구
코드스쿼트라는 교육기관에 들어오기 전에 레벨 테스트로 숫자 야구를 구현했었는데요. 그렇다보니 이 문제가 참 낮설지 않았습니다. 이 문제에서 제가 생각하는 포인트는 2가지 입니다.
- 비교대상 숫자를 선정하는 방법
- 비교대상 숫자와 비교하여 스트라이크, 볼 판별
우선 '비교대상 숫자를 선정하는 방법'은 3자리 수를 만들기 위해 for문 3번을 쓸 수도 있겠지만 저는 그렇게는 하기 싫더라구요. 그래서 111~999까지 돌리는 방법을 정했는데요. 그렇게 하다보면 의도하지 않은 수(중복된 수가 존재하는 수, 0이 포함되는 수)가 나오게 됩니다. 그 경우는 Set<Integer>
를 사용하여 0이 포함되지 않으면서도 중복된 수를 걸려낼 수 있었습니다.
그리고 비교를 하는 경우는 뭐 다를 방법이 있을까요? 10씩 나눠주면서 나머지를 비교하였고 만약 자릿수가 다를 때는 위에서 만든 Set<Integer>
를 이용하여 다른 자리에 존재하는지 유무를 조사하여 볼 판별을 할 수 있었습니다. 아! 그리고 플래그 처리를 통해서 불필요한 계산(스트라이크, 볼 판별이 틀린 경우가 나왔을 때)을 줄이고 정확한 답(모든 판별이 맞았는지)을 구했습니다.
class Solution {
public int solution(int[][] baseball) {
int answer = 0;
for (int i = 111; i < 1000; i++) {
Set<Integer> set = setInit(i);
if(set.contains(0) || set.size() != 3) continue;
boolean flag = true;
for (int[] ints : baseball) {
int target = ints[0];
int num = i;
int strike = 0;
int ball = 0;
while(num != 0) {
int temp = target % 10;
if(num % 10 == temp) strike++;
else if(set.contains(temp)) ball++;
num /= 10; target /= 10;
}
if(strike != ints[1] || ball != ints[2]) {
flag = false;
break;
}
}
if(flag) answer++;
}
return answer;
}
private Set<Integer> setInit(int i) {
Set<Integer> set = new HashSet<>();
String[] numText = String.valueOf(i).split("");
for (String s : numText) {
set.add(Integer.valueOf(s));
}
return set;
}
}
programmers. 섬 연결하기
처음에 방향을 잘못 잡는 바람에 조금 고생했던 문제입니다. 맨 처음에는 '가장 적은 비용 순으로 하나씩 더해가면서 모든 도시를 다 돌때 그때 반복문에서 나오도록' 생각했거든요. 그런데 이것의 문제점은 종료시점이 부정확하고 모든 도시를 다 도는 것과 연결하는 다리 사이와 정확한 관련성이 없다는 것에서 여러 논리적 허점이 들어났습니다.
그렇게 고민끝에 조금 복잡하지만 bfs를 이용하기로 생각했습니다. 아이디어는 간단합니다.
비용이 적은 순으로 해당 노드를 연결했을 때 섬의 개수가 줄어들면 포함시킨다!!
섬의 개수를 구하는 방법은 bfs를 돌리는데 방문 표시를 하면서 Queue위에 모든 경우를 체크할 수 있도록 n개수만큼 반복문 돌리면 됩니다. 그렇기 떄문에 예를들어 (1-2-3, 4-5, 6, 7) 이렇게 연결이 되어있다면 섬의 개수는 4개가 나오고 Queue안에서 1,2,3 돌려지고 4,5 그리고 6 따로 7 따로 이렇게 체크될 것입니다. 아마 bfs 문제를 좀 풀어보셨다면 이런 식으로 푼 문제를 만났을거라 생각합니다.
이렇게 하면 단점은 복잡도가 증가한다는 것입니다. 저도 코드를 짜다가 무한루프를 돌기도 하고 OutOfIndex 에러가 뜨기도 했었는데요. List의 remove()
안에 Integer
타입을 지울 떄는 index 번호로만 지우고, Queue
에 넣기전에 방문 표시를 해야하는데 이후에 하다보니 무한루프에 빠지는 실수를 하였기 때문입니다. 큐에 이미 들어온 이상 그 수가 포함된 것이기 때문에 미리 방문 표시해야 무한루프를 피할수 있습니다. 이제 그럼 코드를 보겠습니다.
class Solution {
public int solution(int n, int[][] costs) {
int answer = 0;
Queue<Cost> queue = initCost(costs); // 오름차순 우선순위큐
List<List<Integer>> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
list.add(new ArrayList<>()); // NullPointException피하기 위해
}
int node = 0;
int curIslandCount = n; // 초기 섬의 개수 -> 6개
while (node < n - 1) { // 만약 도시가 5개면 3개까지 받아야 4개 노드를 구할 수 있음
Cost cost = queue.poll();
int temp = getIslandCount(curIslandCount, n, list, cost); // 노드 연결 후 섬의 개수
if(curIslandCount > temp) { // 만약 섬의 개수가 줄어들었다면
curIslandCount = temp;
answer += cost.cost;
node++;
}
}
return answer;
}
private int getIslandCount(int curIslandCount, int n, List<List<Integer>> list, Cost cost) {
int city1 = cost.city1;
int city2 = cost.city2;
list.get(city1).add(city2); // 서로 연결 기록
list.get(city2).add(city1);
Queue<Integer> queue = new LinkedList<>();
int thisIslandCount = 0; // 노드 연결 후 섬 개수 기록할 변수
boolean[] visit = new boolean[n];
for (int i = 0; i < n; i++) {
if (visit[i] == false && list.get(i).size() == 0) { // 비었거나 방문하지 않을때, 혼자 동떨어진 섬일 경우
visit[i] = true;
thisIslandCount++;
continue;
}
if(visit[i]) continue; // 방문했던 도시
visit[i] = true;
queue.addAll(list.get(i));
for (Integer integer : list.get(i)) {
visit[integer] = true; // 큐에 넣으면 무조건 방문표시
}
while (!queue.isEmpty()) {
int city = queue.poll();
for (Integer integer : list.get(city)) { // 해당 도시와 연결된 다른 도시
if(!visit[integer]) {
visit[integer] = true; // 큐에 넣으면 무조건 방문표시
queue.add(integer);
}
}
}
thisIslandCount++; // 이것도 꼭 섬 +1증가 해야함
}
if(curIslandCount == thisIslandCount) { // 만약 섬의 개수가 줄어들지 않았다면 원복
list.get(city1).remove(list.get(city1).indexOf(city2));
list.get(city2).remove(list.get(city2).indexOf(city1));
}
return thisIslandCount;
}
private Queue<Cost> initCost(int[][] costs) {
Queue<Cost> costList = new PriorityQueue<>();
for (int[] cost : costs) {
costList.add(new Cost(cost[0], cost[1], cost[2]));
}
return costList;
}
}
class Cost implements Comparable<Cost> {
int city1;
int city2;
int cost;
public Cost(int city1, int city2, int cost) {
this.city1 = city1;
this.city2 = city2;
this.cost = cost;
}
@Override
public int compareTo(Cost o) { // 비용 오름차순 순으로 정렬
return this.cost - o.cost;
}
}
'Algorithm > problem solving' 카테고리의 다른 글
Today's Algorithm(2019-01-17) (0) | 2019.01.17 |
---|---|
Today's Algorithm(2019-01-15) (0) | 2019.01.15 |
Today's Algorithm(2019-01-13) (0) | 2019.01.13 |
Today's Algorithm(2019-01-10) (0) | 2019.01.10 |
Today's Algorithm(2019-01-09) (0) | 2019.01.09 |