0을 root로 둔 트리에서
leaf 노드를 출력 해보기

n개의 노드를 담은 배열 n, 각 노드간 연결정보를 가지고 있는 배열 edges를 제공

1. 각 노드별 간선정보를 저장한 배열 link 만들기
2. 탐색 시작 (stack 구현)
3. 방문한 노드와 연결된 노드를 방문하지 않았으면 push
4. 현재 노드와 연결된 노드가 1개일 경우 Leaf Node

 

 

    public void solution(int[] n, int[][] edges){
        boolean[] ck = new boolean[n.length];
        List[] link = new List[n.length];
        Stack<Integer> st = new Stack<Integer>();
        int cur =0;
        int next = 0;

        for(int i=0; i<link.length; i++){
            link[i] = new ArrayList<Integer>();
        }
        for(int i=0; i<edges.length; i++){
            link[edges[i][0]].add(edges[i][1]);
            link[edges[i][1]].add(edges[i][0]);
        }
        //1. 0부터 시작
        st.add(0);
        while(!st.isEmpty()){
            cur = st.pop();
            //System.out.println(cur+" 방문");
            ck[cur] = true; //방문처리
            //연결지점 탐색
            for(int i=0; i<link[cur].size(); i++){
                next = (int) link[cur].get(i);
                if(ck[next]){
                    if(link[cur].size() == 1){
                        System.out.println(cur+" is leafNode");
                    }
                    continue;
                }else{
                    st.push(next);
                }
            }
        }

/*
        for(int i=0; i<link.length; i++){
            System.out.println(link[i]);
        }
*/
    }

    public static void main(String[] args) {
        test06 tc = new test06();

        int[] n = {0,1,2,3,4,5};
        int[][] edges = {{0,1},{2,0},{4,5},{1,3},{1,4}};

        tc.solution(n,edges);

    }

BFS의 가장 기초인 최단거리 구하기문제!

이 문제를 통해서 최단거리 구할때는 BFS가 유리하다는 것을 깨닫게 되었습니다!

 

일단 문제 풀기

 

1. 문제

N×M크기의 배열로 표현되는 미로가 있다.

1 0 1 1 1 1
1 0 1 0 1 0
1 0 1 0 1 1
1 1 1 0 1 1

미로에서 1은 이동할 수 있는 칸을 나타내고, 0은 이동할 수 없는 칸을 나타낸다. 이러한 미로가 주어졌을 때, (1, 1)에서 출발하여 (N, M)의 위치로 이동할 때 지나야 하는 최소의 칸 수를 구하는 프로그램을 작성하시오. 한 칸에서 다른 칸으로 이동할 때, 서로 인접한 칸으로만 이동할 수 있다.

위의 예에서는 15칸을 지나야 (N, M)의 위치로 이동할 수 있다. 칸을 셀 때에는 시작 위치와 도착 위치도 포함한다.

입력

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

출력

첫째 줄에 지나야 하는 최소의 칸 수를 출력한다. 항상 도착위치로 이동할 수 있는 경우만 입력으로 주어진다.

 

 

2. 코드 구현

 

package java_BFS_DFS_basic;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;

class location{
	int w,h,num;
	
	location(int h, int w,int num){
		this.h = h;
		this.w = w;
		this.num = num;
	}
}
public class findMinPath {
	
	static Queue<location> q = new LinkedList<location>();
	static Stack<location> s = new Stack<location>();
	public static void findPath_dfs(int[][] map, boolean[][] ck,int sum) {
	
		location start;
		while(!s.isEmpty()) {
			start = s.peek();
			map[start.h][start.w] = start.num;
			s.pop();
			
			
			//아래로 이동
			if(start.h+1 < map.length && !ck[start.h+1][start.w] && map[start.h+1][start.w] !=0) {
				s.push(new location(start.h+1,start.w,map[start.h][start.w]+1));
				ck[start.h+1][start.w] = true;
			}
			//오른쪽 이동
			if(start.w+1 < map[start.h].length && !ck[start.h][start.w+1] && map[start.h][start.w+1] !=0) {
				s.push(new location(start.h,start.w+1,map[start.h][start.w]+1));
				ck[start.h][start.w+1] = true;
			}
			//왼쪽 이동
			if(start.w-1 >= 0 && !ck[start.h][start.w-1] && map[start.h][start.w-1] !=0) {
				s.push(new location(start.h,start.w-1,map[start.h][start.w]+1));
				ck[start.h][start.w-1] = true;
			}
			//위로 이동
			if(start.h-1 >= 0 && !ck[start.h-1][start.w] && map[start.h-1][start.w] != 0) {
				s.push(new location(start.h-1,start.w,map[start.h][start.w]+1));
				ck[start.h-1][start.w] = true;
			}
			
		}
	}
	
	public static void findPath_bfs(int[][] map, boolean[][] ck,int sum) {
		location start;
		while(!q.isEmpty()) {
			start = q.peek();
			map[start.h][start.w] = start.num;
			q.poll();
			
			
			//아래로 이동
			if(start.h+1 < map.length && !ck[start.h+1][start.w] && map[start.h+1][start.w] !=0) {
				q.add(new location(start.h+1,start.w,map[start.h][start.w]+1));
				ck[start.h+1][start.w] = true;
			}
			//오른쪽 이동
			if(start.w+1 < map[start.h].length && !ck[start.h][start.w+1] && map[start.h][start.w+1] !=0) {
				q.add(new location(start.h,start.w+1,map[start.h][start.w]+1));
				ck[start.h][start.w+1] = true;
			}
			//왼쪽 이동
			if(start.w-1 >= 0 && !ck[start.h][start.w-1] && map[start.h][start.w-1] !=0) {
				q.add(new location(start.h,start.w-1,map[start.h][start.w]+1));
				ck[start.h][start.w-1] = true;
			}
			//위로 이동
			if(start.h-1 >= 0 && !ck[start.h-1][start.w] && map[start.h-1][start.w] != 0) {
				q.add(new location(start.h-1,start.w,map[start.h][start.w]+1));
				ck[start.h-1][start.w] = true;
			}
			
		}
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//int[][] map = {{1,1,1,1},{0,0,1,0},{1,1,1,0},{0,0,1,2}};
		Scanner sc = new Scanner(System.in);
		int n,m;
		n = sc.nextInt();
		m = sc.nextInt();
		
		String[] temp = new String[n];
		int map[][] = new int[n][m];
		for(int i=0; i<n; i++) {
				temp[i] = sc.next();
		}
		
		for(int i=0; i<n; i++) {
			for(int j=0; j<m; j++) {
				map[i][j]=Integer.parseInt(temp[i].substring(j, j+1));
			}
		}
		  
		
		boolean[][] ck = new boolean[n][m];
		
		/*DFS 탐색*/
		//s.push(new location(0,0,1));
		//ck[0][0] = true;
		//findPath_dfs(map,ck,1);
		
		/*BFS 탐색*/
		q.add(new location(0,0,1));
		ck[0][0] = true;
		findPath_bfs(map,ck,1);
		
		System.out.println(map[n-1][m-1]);
		
		for(int i=0; i<n; i++) {
			for(int j=0; j<m; j++) {
				System.out.print(map[i][j]+" ");
			}
			System.out.println();
		}
	}
}

 

 

3. 문제 풀이

 

이 문제를 보면 왜 BFS가 최단거리 탐색에 유리한지 알 수 있습니다.

그림을 볼 필요도 없이..
최단거리에 BFS가 유리한 이유는 사실 DFS는 한 방향만 있는힘껏 탐색하기 때문입니다.

 

아래 그림과 같은 문제가 있다고 가정하겠습니다.

그림 1. 미로 문제

 

 

 

3-1. BFS 탐색

먼저 BFS 탐색을 보겠습니다.

BFS는 큐(Queue)로 구성되어 있기 때문에 분기점으로 나누어져도 분할된 채로 한칸씩 이동합니다.

(1,0) 지점에서 2갈래 길로 나누어지는 시점에서 큐의 상태를 보겠습니다.

그림 2. BFS 탐색 (1)

 

위 그림과 같이 코드에 작성했던 순서대로 아래->오른쪽 탐색을 통해 (2,0)과 (1,1) 두개가 큐에 삽입 됩니다.

그 다음 poll 값 2,0에서 탐색을 진행합니다.

그림 3. BFS 탐색 (2)

 

(2,0)에서는 (3,0)만 갈 수 있으므로, 큐에 (3,0)을 삽입 후 다음으로 진행합니다.

그 다음 poll 값은 (1,1) 입니다.

그림 4. BFS 탐색(3)

 

(1,1)에서 갈 수 있는 길은 (1,2)뿐 이므로 (1,2)를 큐에 삽입합니다.

이런식으로 동작하기 때문에 BFS는 분할 되어도 하나씩 진행이 가능한 것이죠.

 

 

 

3-2. DFS 탐색

같은 시점 DFS의 상태를 보겠습니다.

DFS는 스택으로 구현되기 때문에 아래 그림과 같이 동작합니다.

 

그림 5. DFS 탐색(1)

마찬가지로 (1,0)에서 갈 수 있는 2가지 길 모두 Stack에 Push 합니다.
설정한 탐색 순서에 따라 (2,0), (1,0)을 삽입 합니다.

그 다음 하나를 pop을 합니다.

그림 6. DFS 탐색(2)

(1,1)에서 갈 수 있는 (1,2)를 stack에 push 합니다.

그리고 하나를 pop 합니다.

 

그림 7. DFS 탐색(3)

 

이렇듯 DFS 탐색은 한쪽 길을 끝까지 탐색합니다.

 

 

 

4. 결과

결과적으로 BFS/DFS 탐색은 아래 그림과 같은 결과를 보여줍니다.

 

그림 8. DFS BFS 결과 값

 

 

위 결과에서 보여주듯이 DFS 탐색은 한 방향을 쭉 탐색하기 최소 거리 구하기에는 적합하지 않습니다.

그래서 최소거리를 구할땐 BFS를 사용하는 것이죠!

 

'알고리즘 공부 > 알고리즘 문제' 카테고리의 다른 글

트리 dfs 탐색  (0) 2021.04.23
나누어 떨어지는 숫자 배열  (0) 2019.03.12
문자열 내 맘대로 정렬하기  (0) 2019.03.12
빙고 개수 카운트하기  (0) 2019.01.31
배열 회전 결과값 확인하기  (1) 2019.01.26

프로그래머스 lv.1 문제


사실 문제가 어려워서 글을 작성하는 것이 아니고

'자바 - 컬렉션과 제네릭' 파트 부분이 많이 부족하다는 것은 인지 하고 있었지만


제가 10줄이 넘어가게 코드를 짤 동안 이것을 아는 사람들은 1~2줄 만에 끝내버리는 격차를 발견 후

살짝 현타가 와서 정리합니다 ㅋㅋㅋㅋㅋ

늦기 전에 다시 공부하기 ㅠㅠ 컬렉션 제네릭 람다식..


[문제 설명]

array의 각 element 중 divisor로 나누어 떨어지는 값을 오름차순으로 정렬한 배열을 반환하는 함수, solution을 작성해주세요.
divisor로 나누어 떨어지는 element가 하나도 없다면 배열에 -1을 담아 반환하세요.

[제한사항]
  • arr은 자연수를 담은 배열입니다.
  • 정수 i, j에 대해 i ≠ j 이면 arr[i] ≠ arr[j] 입니다.
  • divisor는 자연수입니다.
  • array는 길이 1 이상인 배열입니다.
[입출력 예]

arr                  divisor     return

[5, 9, 7, 10] 5              [5, 10]

[2, 36, 1, 3] 1          [1, 2, 3, 36]

[3,2,6]         10          [-1]


[문제 풀이]

1. arr 배열에 있는 수를 divisor로 나누어 떨어지면 ArrayList에 add

2. ArrayList를 다시 asnwer로 옮긴 후 정렬해서 return


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.ArrayList;
import java.util.Arrays;
class Solution {
  public int[] solution(int[] arr, int divisor) {
      //int[] answer = {};
      ArrayList<Integer> arr_list = new ArrayList<Integer>();
      int cnt=0;
      for(int i=0; i<arr.length; i++){
          if(arr[i]%divisor == 0){
              arr_list.add(arr[i]);
          }
      }
      
      if(arr_list.size()==0){
          arr_list.add(-1);
      }
      int[] answer = new int[arr_list.size()];
      for(int j=0; j<arr_list.size(); j++){
          answer[j] = arr_list.get(j);
      }
      Arrays.sort(answer);
      return answer;
  }
}
cs


위의 내용을 이렇게도 풀 수 있습니다!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.Arrays;
class Solution {
  public int[] solution(int[] arr, int divisor) {
 
        int[] answer = Arrays.stream(arr).filter(factor -> factor % divisor == 0).toArray();
        int[] answer_null = {-1};
        
        Arrays.sort(answer);
        if(answer.length==0) {
            return answer_null;
        }
        else        
            return answer;
  }
}
cs


오히려 어려운 문제 풀었을 때 보다 이렇게 내가 어리석다는 것을 깨달을 때가 더욱 자극 되는 것 같습니다.

(관련 내용 정리하기 ~)


'알고리즘 공부 > 알고리즘 문제' 카테고리의 다른 글

트리 dfs 탐색  (0) 2021.04.23
백준 (2178) - 미로탐색 (java)  (0) 2019.06.04
문자열 내 맘대로 정렬하기  (0) 2019.03.12
빙고 개수 카운트하기  (0) 2019.01.31
배열 회전 결과값 확인하기  (1) 2019.01.26

요즘 자소서만 쓰다보니 코딩에 무뎌져서 감각 좀 살릴 겸

차근차근 다시 lv.1 짜리 위주로 문제풀고있는데 정렬 문제가 생각이 안나서 멘붕


그래서 정리 할 겸 작성 해 봅니다.



시작!


내 마음대로 정렬하기

[문제 설명]

문자열로 구성된 리스트 strings와, 정수 n이 주어졌을 때, 각 문자열의 인덱스 n번째 글자를 기준으로 오름차순 정렬하려 합니다. 예를 들어 strings가 [sun, bed, car]이고 n이 1이면 각 단어의 인덱스 1의 문자 u, e, a로 strings를 정렬합니다.

[제한 조건]
  • strings는 길이 1 이상, 50이하인 배열입니다.
  • strings의 원소는 소문자 알파벳으로 이루어져 있습니다.
  • strings의 원소는 길이 1 이상, 100이하인 문자열입니다.
  • 모든 strings의 원소의 길이는 n보다 큽니다.
  • 인덱스 1의 문자가 같은 문자열이 여럿 일 경우, 사전순으로 앞선 문자열이 앞쪽에 위치합니다.



[입출력 예]

strings                 n return
[sun, bed, car]         1 [car, bed, sun]
[abce, abcd, cdx] 2 [abcd, abce, cdx]

[입출력 예 설명]
입출력 예 1
sun, bed, car의 1번째 인덱스 값은 각각 u, e, a 입니다. 이를 기준으로 strings를 정렬하면 [car, bed, sun] 입니다.

입출력 예 2
abce와 abcd, cdx의 2번째 인덱스 값은 c, c, x입니다. 따라서 정렬 후에는 cdx가 가장 뒤에 위치합니다. abce와 abcd는 사전순으로 정렬하면 abcd가 우선하므로, 답은 [abcd, abce, cdx] 입니다.

[문제 풀이]

문제 푸는 과정

1. 기본문제 해결 방법이 안떠올라 멘붕하기

왜냐면 맨날 문제 풀다가 정렬이 필요한 경우 자바에서 지원해주는 Arrays.sort() 메서드를 사용했기 때문 ㅋㅋㅋㅋ

2.  정렬 하기

nlog(n)의 기댓값을 갖는 퀵정렬은 구현하기 힘드니(?) 선택/버블/삽입 정렬 중 선택한다.

(개인적으로 선택 정렬이 제일 외우기 쉬우니 선택 정렬로 구현)

3. 정렬 조건에 문자열을 기준으로 할지 선택한다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public String[] solution(String[] strings, int n) {
        String[] answer = {};
        int min;
        String temp;
        //선택 정렬 구현하기
        for(int i=0; i<strings.length-1; i++) {
            min = i;
            for(int j=i+1; j<strings.length; j++) {
                //비교해서 가장 작은 값을 찾는다.
                System.out.println(" "+strings[min].substring(n, n+1)+" vs "+strings[j].substring(n, n+1));
                if(strings[min].substring(n, n+1).compareTo(strings[j].substring(n, n+1))>0) {
                    min = j;
                }
                //n번째 문자까지 같다면 걍 문자 비교하기
                else if(strings[min].substring(n, n+1).compareTo(strings[j].substring(n, n+1))==0) {
                    if(strings[min].compareTo(strings[j])>0) {
                        min = j;
                    }
                }
              }
            //min값을 i번째와 바꾼다.
            temp = strings[i];
            strings[i] = strings[min];
            strings[min] = temp;
        }
        
        for(String k : strings) {
            System.out.println(k);
        }
        return strings;
    
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        programmers_SuitMyselfSort s = new programmers_SuitMyselfSort();
        
        String[] strings = {"sun","bed","car"};//{"abce","abcd","cdx"};
        int n = 1;
        
        s.solution(strings, n);
 
    }
cs


풀고 보니 어려운게 아니고 정리할 것도 딱히 없어보인 문제

해결방법이 갑자기 안떠올라서 ㅠㅠ 

어쨋거나 정렬이 안떠올랐다는건 기본기가 부족하다는 것이니, 다시 복습하는 시간을 가져야 겠습니다.


각 정렬 알고리즘 구현 하는 시간을 가져봐야겠네요.





프로그래머스 모의테스트 마지막 문제였던 빙고 문제

솔직히 다른 알고리즘이 자신있는건 아니지만

현재 가장 자신없는 알고리즘 부분은 BFS/DFS.. 탐색!! 부분입니다.


그래서 문제로 다중 행렬 나온다음에 넓이 체크하라는거 나오면 솔직히 겁부터 나긴 합니다. 

탐색 알고리즘을 완전히 이해한 후 문제를 풀려고 했으나 

일단 그냥 풀어보고 싶은 알수없는 오기(?) 발동으로 빙고 문제를 풀어봤습니다.

막 풀어서 코드가 길어요..


그럼 풀어봅시다

[문제]

* 빙고는 NxN 크기의 게임 보드 칸에 1부터 NxN까지의 자연수를 중복 없이 하나씩 적은 후 숫자를 하나씩 지워나가는 게임입니다.

*  이때, 가로, 세로, 대각선 방향으로 한 줄에 적힌 숫자를 모두 지울 경우 빙고를 1개 만들었다고 합니다.

- 다음은 4X4 크기의 게임 보드를 이용해 게임을 진행한 예시입니다.

- 위와 같이 각 칸에 숫자가 적혀 있을 때, 위 게임 보드에서 순서대로 지운 숫자가 [14,3,2,4,13,1,16,11,5,15]인 경우 아래와 같이 빙고 3개가 만들어집니다.

빙고 게임 보드에 적힌 숫자가 담겨있는 배열 board, 게임 보드에서 순서대로 지운 숫자가 들어있는 배열 nums가 매개변수로 주어질 때,

board에서 nums에 들어있는 숫자를 모두 지우면 몇 개의 빙고가 만들어지는지 return하도록 solution함수를 완성해주세요.


[제한사항]

board는 게임 보드 칸에 적힌 숫자를 뜻하는 NxN크기의 2차원 배열이며, N은 2 이상 500이하의 자연수입니다.

board의 각 칸에는 1 이상 NxN이하의 자연수가 중복 없이 하나씩 들어있습니다.

nums는 board에서 지울 숫자가 들어있는 배열이며, 길이는 1 이상 NxN이하입니다.

nums에 들어있는 숫자는 1 이상 NxN이하의 자연수이며, 중복된 수가 들어있지 않습니다.



[문제 풀이]

저는 다음과 같은 순서로 문제를 풀었습니다.

1. num 배열에 있는 수를 하나씩 체크하며 보드 판에 해당 숫자가 있는지를 확인하고, 있으면 0으로 바꾸어 준다.

2. 바꾸어진 빙고판을 count_bingo() 함수로 보내어 빙고 갯수를 판별한다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package pracitce_note;
 
public class mock_test03 {
    //빙고판 확인 함수
    public static int[][] confirm_borad(int[][] b,int num) {
        
        for(int i=0; i<b.length; i++) {
            for(int j=0; j<b.length; j++) { //숫자 있으면 0으로 변경
                if(b[i][j]==num) {
                    b[i][j] = 0;
                }
            }
        }
        return b;
    }
    //디버깅용 출력 함수
/*public static void print(int[][] b) {
        for(int i=0; i<b.length; i++) {
            for(int j=0; j<b.length; j++) {
                System.out.print(b[i][j]+" ");
            }
            System.out.println();
        }
    }*/
    //빙고 카운트
    public static void count_bingo(int[][] board) {
        
        //가로와 세로를 체크해 줄 V - H 배열 생성
        int v[] = new int[board.length];
        int h[] = new int[board.length];
        int c[] = new int[2]; //대각선은 두개 뿐 
        int count =0;
        //0으로 바뀐거 체크하면서 가로 / 세로/ 대각선 체크
            for(int i=0; i<board.length; i++) {
                for(int j=0; j<board.length; j++) {
                    //가로 카운트
                    if(board[i][j]==0) {
                        v[i]++//가로 체크
                        h[j]++//세로 체크
                        if(i==j) { //대각선 체크
                            c[0]++;
                        }
                        if(i+j==board.length-1) {
                            c[1]++;
                        }
                    }
                }
            }
        //체크값 확인해서 빙고면 count++    
        for(int k=0; k<v.length; k++) {    
             if(v[k] == v.length) {
                 count++;
             }
             if(h[k] == v.length) {
                 count++;
             }
        }
        //대각선은 어떤 빙고판이든 2개라서.. 따로 빼서 체크..
         if(c[0]==v.length) {
             count++;
         }
         if(c[1]==v.length) {
             count++;
         }
         //count 값
         System.out.println(count);
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        int[][] board = {{11,13,15,16},{12,1,4,3},{10,2,7,8},{5,14,6,9}};
        int[] num = {14,3,2,4,13,1,16,11,5,15};
        
        /* solution
         * 1. num에 있는 숫자를  하나씩 비교하며 board에 있는경우 0으로 바꾼다
         * 2. 바꾸어진 board에 빙고 부분을 카운트 한다.
         * */
        //num 하나씩 보내면서 체크하기
        for(int i=0; i<num.length; i++) {
            confirm_borad(board,num[i]);
        }
        //print(board);
        
        count_bingo(board); //빙고 체크하기
 
    }
 
}
 

cs


효율성은 O(2n^2)? 되는거같은뎅 

풀고보니 num 체크하면서 바로바로 카운트하면 함수를 두개로 나눌 필요가 없어보이긴 합니다


근거없는 자신감이지만 탐색 알고리즘을 공부하고나면 코드가 엄청 줄고 효울성도 올라갈 것 같은 기분이 ㅋㅋ

빨리 탐색 알고리즘 공부를 해야겠네요

 

프로그래머스 모의테스트 문제

두개의 배열 arrA, arrB를 받아서 

arrA를 회전시켜 arrB를 만들 수 있으면 true 아니면 false 리턴하는 함수 만들기!


[문제]

* 배열의 회전이란 모든 원소를 오른쪽으로 한 칸씩 이동시키고, 마지막 원소는 배열의 맨 앞에 넣는 것을 말합니다.

* 두 배열 arrA와 arrB가 매개변수로 주어질 때, arrA를 회전해 arrB로 만들 수 있으면 true를, 그렇지 않으면 false를 return 하는 solution 함수를 작성해주세요.


[제한 조건]

arrA는 길이가 1 이상 1,500 이하인 배열입니다.

arrA의 원소는 0 이상 1,500 이하인 정수입니다.

arrB는 길이가 1 이상 1,500 이하인 배열입니다

arrB의 원소는 0 이상 1,500 이하인 정수입니다.



[문제풀이]

제가 생각한 솔루션은 다음과 같습니다.

ArrayList 이용하기!

사실, Queue를 이용해도 상관 없겠지만 이런 문제의 경우 전 ArrayList가 편해서 이걸로 풀었습니다.

1. ArrayList a를 만들어서 a에 arrA 배열을 넣는다.

2. confirm 메서드를 만든다.

2-1) a.size()와 arrB 배열 크기가 다르면 false return

2-2) a의 원소 와 arrB의 원소를 하나씩 비교해서 같으면 ture 아니면 false 리턴

3. ArrayList a를 순환시켜 arrB를 만들 수 있는지 확인한다.

confirm메서드에 a와 arrB를 던져서 answer값 받기


이것을 코드로 옮기기!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class mock_test01 {
    //confirm 메서드 선언
    public static boolean confirm(ArrayList<Integer> a,int[] arrB) {
        boolean answer = true;
        //배열 크기가 다르면 false
        if(a.size() != arrB.length){
            answer = false;
            return answer;
        }
 
        //배열 원소 하나씩 비교하기
        else 
            for(int i=0; i<arrB.length; i++) {
                //if(!a.get(i).equals(arr2[i])) {
                //System.out.println("a.get = "+a.get(i) + " arr2 = "+arrB[i]);
                if(!a.get(i).equals(arrB[i])) {
                    answer = false;
                    break;
                }
            }
            return answer;
        
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        int[] arrA = {1,2,3,4,5,6}; //4,1,2,3 -> 3,4,1,2 -> 2,3,4,1 -> 1,2,3,4
        int[] arrB = {6,1,2,3,4,5};
        int temp = arrA[arrA.length-1]; //arrA의 마지막 값
        boolean answer = false;
        ArrayList<Integer> a = new ArrayList<Integer>();
 
        //ArrayList a에 arrA 원소 넣기
        for(int i=0; i<arrA.length; i++) {
            a.add(arrA[i]);
        }
        
        //arrA 순환시키기
        for(int j=0; j<arrA.length; j++) {
             a.add(0,temp);             //배열 맨 마지막 값을 맨 앞으로 삽입
             a.remove(arrA.length);     //맨 마지막값은 삭제
             //System.out.println(a);
             
             //만들 수 있으면 break
             if(confirm(a,arrB)) {  //순환된 ArrayList a로 arrB를 만들 수 있는지 확인
                 answer = true;
                 break;
             }
             //순환 후 맨 마지막값 다시 temp에 넣기
             temp = a.get(arrA.length-1);
        }
        
         System.out.println(answer);
    }
}
cs


효율성 검사가 없어서 통과 되긴했네요

지금은 무식하게 풀고있긴 하지만 계속 연습하다보면 더 좋은 방법들을 찾을 수 있을것 같습니다.


/* 2019 - 01 - 31 수정 */

풀이 확인하니 배열 자체를 순환시키면 됬는데, 저는 왜  위의 풀이처럼 저렇게 풀었는지 이해가 안가는군여...

역시 모르면 피곤해지나봅니다 ㅠㅠ

덕분에 Arrays.equals(arrA,arrB)처럼 간단하게 자바에서 배열 원소를 비교해주는 클래스를 지원해준다는 것을 하나 배워가네요 ㅋㅋ


수정된 풀이 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class mock_test01 {
    
    public static boolean circulation(int[] arrA,int[] arrB) {
        
        int first;
        boolean answer = false;
        
        for(int j =0; j<arrA.length; j++) {
            //배열 순회하기 
            first = arrA[0];
            //한바퀴 돌때까지 순회
          for(int i=0; i<arrA.length-1; i++) {
                arrA[i] = arrA[i+1];
            }
            arrA[arrA.length-1= first;
            //arrA랑 arrB랑 같아지면 break
            if(Arrays.equals(arrA, arrB)) {
                answer = true;
                break;
            }
        }
        return answer;
    }
    
    
    public static void main(String[] args) {
        int[] arrA = {1,2,3,4,5,6}; //4,1,2,3 -> 3,4,1,2 -> 2,3,4,1 -> 1,2,3,4
        int[] arrB = {1,2,3,4,5,6};
        boolean answer = false;
    
        System.out.println(circulation(arrA,arrB));
        
    }
cs


공부합시다!!!


'알고리즘 공부 > 알고리즘 문제' 카테고리의 다른 글

문자열 내 맘대로 정렬하기  (0) 2019.03.12
빙고 개수 카운트하기  (0) 2019.01.31
도로에 가로등 전구 달기  (0) 2019.01.26
숫자를 한글로 읽기  (0) 2019.01.06
완주하지 못한 선수  (0) 2018.12.10

흠 프로그래머스 모의테스트 문제를 풀어보는데

주로 효율성 검사에서 항상 문제가 생기네요 ㅠㅠ

효율성 생각해서 문제 푸는건 항상 어려운것 같습니다 ㅋㅋ


아무튼 오늘 문제는 도로에 가로등 전구 달기!


[문제]

서울시에 일직선 모양의 새로운 도로가 생겼습니다. 새로운 도로의 전체 길이는 L이고 도로에는 총 n개의 가로등이 세워졌습니다. 이 도로의 모든 가로등에 전구를 사서 달려고 합니다.

 *  전구를 선택하는 기준은 다음과 같습니다.


- 전구는 길의 좌측, 우측 방향으로 각각 d 길이만큼 길을 밝힐 수 있고, d는 자연수입니다.

- 모든 가로등에는 같은 종류(d 값이 같은)의 전구를 달아야 합니다.

- 안전을 위하여 도로위에 어두운 부분이 있어서는 안 됩니다.

- 이때, d 값이 충분히 크다면 전체 도로를 밝게 비출 수 있지만, d 값이 작아진다면 도로 위에 빛이 닿지 않는 부분이 생길 수도 있습니다. 

- 따라서, 도로 위에 어두운 부분이 생기지 않도록 하는 d 값 중 최솟값을 구하려고 합니다.

- 전체 도로의 길이 L, 가로등이 세워져 있는 위치가 들어있는 배열 v가 매개변수로 주어질 때, 위의 모든 조건을 만족하는 d 의 최솟값을 return 하도록 solution 함수를 완성해주세요.


[제한사항]

- L은 1 이상 1,000,000,000 이하의 자연수입니다.

- v에는 가로등의 위치정보가 들어있습니다.

- 가로등의 위치는 0 이상 l 이하의 정수이며, 같은 위치에 2개 이상의 가로등이 있는 경우는 주어지지 않습니다.

- 가로등의 개수는 1이상 1,000 이하의 자연수입니다.



[문제 풀이]

제가 생각한 풀이법은 무식하게 다음과 같이 풀었습니다....

(사실 풀면서 이거 효율성 문제 걸릴거같은데 라고 생각했지만 딱히 다른 방법이 생각안나서 ㅋㅋ)

1. 배열을 정렬한다.

2. 배열의 첫번째 위치(가로등 첫번째 위치)가 0인지 확인한다.

3. 배열의 끝의 위치(가로등 마지막 위치)가 L(길이 값)인지 확인한다.

4. 2) or 3)의 경우가 false라면 둘 중에 큰 값 max를 구한다.

5. 정렬된 배열을 i+1 ,i를 비교해서 가장 큰 차 max_arr를 구한다.

6. max 값과 max_arr를 비교한다.

7. max가 클 경우 answer = max

8. max_arr가 클 경우 짝수일 경우 answer = max/2  홀수일 경우 answer = max/2+1


그럼 코딩해봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class mock_test02 {
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        int[] v = {2,9,3,6};
        int answer;
        int l = 11;
        
        //배열 정렬하기
        Arrays.sort(v);
        int max = 0;
        int max_arr=0;
        
        //가로등 첫번째 위치와 끝 위치가 0,L인지 확인하기
        if(v[0]-0 < l-v[v.length-1]) {
            max = l-v[v.length-1];
            answer = max;
            System.out.println("l과의 거리 "+max);
        }
        else {
            max = v[0]-0;
            answer = max;
            System.out.println("0과의 거리 "+max);
        }
        
        //배열 내 최댓값 구하기
        for(int i=0; i<v.length-1; i++){
            if(max_arr<v[i+1]-v[i]){
                max_arr = v[i+1]-v[i];
            }
        }
        //홀수 짝수 구분하기 ->이유 : d는 정수이기 때문에 max_arr이 1.5이면 최솟값은 2이기 때문
        if(max_arr%2==0) {
            max_arr = max_arr/2;
        }
        else {
            max_arr = (max_arr/2)+1;
        }
        
 
        //마지막 max값과 max_arr값 구해서 큰것이 최솟값이 된다.
        if(max<max_arr) {
            answer = max_arr;
        }
        else
            answer = max;
 
        System.out.print(answer);
    }
 
}
cs


음.. 정확성 테스트는 통과 했지만 효율성 검사에서 실패했네요 ㅠㅠ

Arrays.sort()만 써도 효율성에서 런타임아웃되던데 

다른 라이브러리를 사용하는 방법이 있거나 다른 간단한 솔루션이 있을것 같습니다.


생각나거나 나중에 문제풀다 생각나면 해결해보기로 ㅎㅎ


'알고리즘 공부 > 알고리즘 문제' 카테고리의 다른 글

문자열 내 맘대로 정렬하기  (0) 2019.03.12
빙고 개수 카운트하기  (0) 2019.01.31
배열 회전 결과값 확인하기  (1) 2019.01.26
숫자를 한글로 읽기  (0) 2019.01.06
완주하지 못한 선수  (0) 2018.12.10

숫자를 한글로 읽기


메이플스토리를 하다보면 한글날에 데미지 스킨을 주는데,  이 데미지 스킨을 사용하면

숫자로 출력하던 데미지들이 한글로 변경이 됩니다!


그럼 자바를 통해서 숫자를 한글로 읽을 수 있도록 하는 문제를 풀어봅시다.


[제한사항]

주어진 숫자 num는 1조 미만의 숫자 입니다.

1의 자릿수 이상에서의 1은 "일"로 읽지 않고 공백으로 취급합니다.

ex)1231 의 경우 

"일천이백삼십일" (X)

"천이백삼십일" (O)


[입출력 예]

1234

"천이백삼십사" 


49032

 "사만구천삼십이"


[문제 풀이]

import java.util.*;

public static void main(String[] args) {

// TODO Auto-generated method stub

int num;

Scanner s = new Scanner(System.in);  //숫자 num을 입력 받습니다.

num = s.nextInt();

String answer = "";

    

    String num_string = String.valueOf(num);  //int형은 substring이 안되기 때문에 문자형으로 받아 주어야 합니다.


        String[] han1 = {"","일","이","삼","사","오","육","칠","팔","구"};

        String[] han2 = {"","십","백","천"}; //십, 백,천 단위를 구분하기 위해 배열을 선언 합니다.

        String[] han3 = {"","만","억"};  // 천단위로 끊어서 단위가 올라가기 때문에 만이상 단를 구분해 줄 배열을 선언합니다.


        StringBuffer result = new StringBuffer();  // StringBuffer 선언

        int num_len = num_string.length();      // num의 길이 측정


        for(int i=num_len-1; i>=0; i--){  

           // 십단위 이상의 1은 읽지 않기 때문에 마지막 일을 제외한 1의 경우 "일"로 읽지 않음

            if(han1[Integer.parseInt(num_string.substring(num_len-i-1, num_len-i))]=="일" && num_len-i != num_len) {

                result.append(han1[0]);

            //System.out.println(result.append(han1[0])); 디버깅용

            }

            else { 

                result.append(han1[Integer.parseInt(num_string.substring(num_len-i-1, num_len-i))]);

            //System.out.println(result.append(han1[Integer.parseInt(num_string.substring(num_len-i-1, num_len-i))])); //디버깅용

            }

            // i는 자릿 수 이기 떄문에 4로 나눈 나머지가  3이면  천 / 나머지가 2이면 백 / 나머지가 1이면 십 /4로 나누어떨어지면 안읽음

   // 9090과 같이 0을 제외한 백단위 이상 숫자를 구분하여 읽기 위한 조건문

                if(Integer.parseInt(num_string.substring(num_len-i-1, num_len-i))>0);

                result.append(han2[i%4]);

            //System.out.println(result.append(han2[i%4])); //디버깅용

            //만단위 이상으로 올라갈 경우 처리하기 위함

            if(i%4==0)

            //System.out.println(result.append(han3[i/3])); //디버깅용

            result.append(han3[i/3]); 

            

        }

      //   result.append(han1[Integer.parseInt(num_string.substring(num_len-1, num_len))]); //디버깅용

        answer = result.toString(); // String Buffer랑 String이랑 다르기 때문에 String Buffer를 String으로 변경해주어야 합니다.

   //System.out.println(restult); // String으로 retrun할거 아니면 result 그대로 출력하면 됩니다.

     System.out.println(answer);

}

----------------------------------------------------------------------------------------------------------------------------------------------

for문을 돌릴때 0부터 시작하게 한다면 어떻게 작성해야할지 궁금해서 for문의 조건문 중 i를 0부터 시작하도록 변경 해 보았습니다.


[for문 0부터 시작 차이점]

 for(int i=0; i<num_len; i++){

        // 십단위 이상의 1은 읽지 않기때문에 0으로 설정하고 마지막 자리가 1일때만 읽도록 수정

    /* 초록색으로 표기된 부분이 변경된 부분입니다. */

   // num은 0부터 시작하기에 1을 빼주어야 정확한 계산이 가능 해집니다.

            if(han1[Integer.parseInt(num_string.substring(i, i+1))]=="일" && i != num_len-1) {

                result.append(han1[0]);

            //System.out.println(result.append(han1[0]));

            }

            else {

                result.append(han1[Integer.parseInt(num_string.substring(i, i+1))]);            

            }

           //i는 자릿 수 이기 떄문에 4로 나눈 나머지가  3이면  천 / 나머지가 2이면 백 / 나머지가 1이면 십 /4로 나누어떨어지면 안읽음

                if(Integer.parseInt(num_string.substring(i, i+1)));

                result.append(han2[(num_len-1-i)%4]);

              //System.out.println("천 단위 계산 :"+result.append(han2[(num_len-1-i)%4]));

           

            //만단위 이상으로 올라갈 경우 처리하기 위함

            if((num_len-1-i)%4==0)

            result.append(han3[(num_len-1-i)/3]);

//%로 계산하면 나머지가 다시 1로 떨어지는 경우 만을 출력하기 때문에 나눈 값의 몫으로 계산해야 만단위 이상에도 에러가 나지 않습니다.

            //System.out.println("만 단위 계산 : "+result.append(han3[(num_len-1-i)/3])); 

            //result.append(han3[i/3]);

        }

        


결국 조건문만 변경하면 똑같은 문제인것 같습니다.  계산 속도에서 당연 차이는 없어보이네요..

실행 시간은 O(n)이 되겠네요








 

+ Recent posts