[프로그래머스] 타겟넘버 (java) Dfs

2020-01-24

타겟넘버 (programers > lev2 > Dfs_Bfs)

문제 링크

문제설명

n개의 음이 아닌 정수가 있습니다. 이 수를 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다. 예를 들어 [1, 1, 1, 1, 1]로 숫자 3을 만들려면 다음 다섯 방법을 쓸 수 있습니다.

-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3

사용할 수 있는 숫자가 담긴 배열 numbers, 타겟 넘버 target이 매개변수로 주어질 때 숫자를 적절히 더하고 빼서 타겟 넘버를 만드는 방법의 수를 return 하도록 solution 함수를 작성해주세요.

제한사항
  • 주어지는 숫자의 개수는 2개 이상 20개 이하입니다.
  • 각 숫자는 1 이상 50 이하인 자연수입니다.
  • 타겟 넘버는 1 이상 1000 이하인 자연수입니다.
입출력 예
numbers target return
[1, 1, 1, 1, 1] 3 5


풀이

public class prog_2_타겟넘버 {

	static int answer = 0;
	
	static public void dfs(int numbers[], int idx, int sum, int target) {
		//기저 조건
		if(idx == numbers.length) {
			if(sum == target)
				answer ++;
		}
		
		else if(idx<numbers.length) {
			dfs(numbers,idx+1, sum+numbers[idx], target);
			dfs(numbers,idx+1, sum-numbers[idx], target);
		}
		
	}
	
	
	static public int solution(int[] numbers, int target) {
		
		dfs(numbers,0,0,target);
		
		return answer;
	}
	
	public static void main(String[] args) {
		int n[] = {1,1,1,1,1}; int target = 3;
		
		System.out.println(solution(n,target));
	}
}


후기 (40min)

dfs 문제.. 항상 애를 먹인다…!

sum에 더한거 뺀거를 하나씩 해주면 갯수만큼 + - 를 반복해준다 라는 생각을 쉽게 할 수가 없었따….! 방법만 생각해내면 쉬우나 늘 그 방법 생각해내기가 어렵다는 거…


tip

  1. 항상 재귀를 한번만 돌필요는 없다는거
  2. 재귀 변수에 뭘 넣어줄지 잘 생각해낸다면 sum만 가지고 쉽게 문제를 풀 수 있다!!


Read More

[프로그래머스] 피보나치 수 (java) Recursion

2020-01-24

피보나치 수(programers > lev2 > Recursion)

문제 링크

문제설명

피보나치 수는 F(0) = 0, F(1) = 1일 때, 1 이상의 n에 대하여 F(n) = F(n-1) + F(n-2) 가 적용되는 수 입니다.

예를들어

  • F(2) = F(0) + F(1) = 0 + 1 = 1
  • F(3) = F(1) + F(2) = 1 + 1 = 2
  • F(4) = F(2) + F(3) = 1 + 2 = 3
  • F(5) = F(3) + F(4) = 2 + 3 = 5

와 같이 이어집니다.

2 이상의 n이 입력되었을 때, n번째 피보나치 수를 1234567으로 나눈 나머지를 리턴하는 함수, solution을 완성해 주세요.

제한 사항
  • n은 1이상, 100000이하인 자연수입니다.
입출력 예
n return
3 2
5 5
입출력 예 설명

피보나치수는 0번째부터 0, 1, 1, 2, 3, 5, … 와 같이 이어집니다.


풀이

	//시간 초과........!! (답은 맞음)
	static public int fib(int n) {
		int answer = 0;

		if(n == 0)
			return 0;
		
		if(n == 1)
			return 1;
		
		answer = fib(n-1)%1234567 + fib(n-2)%1234567;
		
		return answer %1234567;
	}
	
	
	  static public int solution(int n) {
	      int answer = 0;
	      
	      if(n == 1)
	    	  return 1;
	      
	      int a = 0; // n-1 값 넣기
	      int b = 1; // n-2 값 넣기
	      
	      for(int i=2; i<=n; i++) {

	    	  answer = a + b;
	    	  
	    	  a = b% 1234567;
	    	  b = answer% 1234567;
	      } // a= b; b = a+b; 를 하니까 b = b+b 가 되었는데.. 그것도 모르고 계속 저렇게 함...
	      
	      return answer % 1234567;
	  }
	
	public static void main(String[] args) {
		System.out.println(solution(3));
		System.out.println(fib(3));
	}


후기 (20min)

a와 b가 반복되는 부분에서 뭘 변수로 넣어줘야 하는지 헤매다가 시간이 훌쩍 지나버렸다..허허 이렇게 쉬운 문제도 안풀다가 다시 풀면 까먹는 불상사가..

또, 재귀로 풀면 큰 수 일 경우에 같은 숫자도 여러번 반복하기 때문에 시간초과가 뜬다. for문은 전 값과, 전전 값을 가지고 있기 때문에 시간초과가 뜨지않고 문제를 해결할 수 있었다!


tip

  1. 재귀로 풀때 시간초과가 뜨는 문제는 dp로 풀어야하기 때문에 생각을 잘 해줘야 할것 같다!
  2. 피보나치 까먹지말자! 변수에 뭘 넣고 반복해줘야 하는지도!


Read More

[프로그래머스] 기능개발 (java) Queue

2020-01-24

기능개발(programers > lev2 > Stack_Queue)

문제 링크

문제설명

프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100%일 때 서비스에 반영할 수 있습니다.

또, 각 기능의 개발속도는 모두 다르기 때문에 뒤에 있는 기능이 앞에 있는 기능보다 먼저 개발될 수 있고, 이때 뒤에 있는 기능은 앞에 있는 기능이 배포될 때 함께 배포됩니다.

먼저 배포되어야 하는 순서대로 작업의 진도가 적힌 정수 배열 progresses와 각 작업의 개발 속도가 적힌 정수 배열 speeds가 주어질 때 각 배포마다 몇 개의 기능이 배포되는지를 return 하도록 solution 함수를 완성하세요.

제한 사항
  • 작업의 개수(progresses, speeds배열의 길이)는 100개 이하입니다.
  • 작업 진도는 100 미만의 자연수입니다.
  • 작업 속도는 100 이하의 자연수입니다.
  • 배포는 하루에 한 번만 할 수 있으며, 하루의 끝에 이루어진다고 가정합니다. 예를 들어 진도율이 95%인 작업의 개발 속도가 하루에 4%라면 배포는 2일 뒤에 이루어집니다.
입출력 예
progresses speeds return
[93,30,55] [1,30,5] [2,1]
입출력 예 설명

첫 번째 기능은 93% 완료되어 있고 하루에 1%씩 작업이 가능하므로 7일간 작업 후 배포가 가능합니다. 두 번째 기능은 30%가 완료되어 있고 하루에 30%씩 작업이 가능하므로 3일간 작업 후 배포가 가능합니다. 하지만 이전 첫 번째 기능이 아직 완성된 상태가 아니기 때문에 첫 번째 기능이 배포되는 7일째 배포됩니다. 세 번째 기능은 55%가 완료되어 있고 하루에 5%씩 작업이 가능하므로 9일간 작업 후 배포가 가능합니다.

따라서 7일째에 2개의 기능, 9일째에 1개의 기능이 배포됩니다.


풀이

    static public int[] solution(int[] progresses, int[] speeds) {
    	
    	LinkedList<Integer> list = new LinkedList<Integer>();
    	Queue<Integer> qu = new LinkedList<Integer>();
    	int idx = 0;
    	int day = 0;
    	
    	
    	for(int i=0; i<progresses.length; i++)
    		qu.offer(progresses[i]);
    	
    	while(!qu.isEmpty()) {
    		day++;
    		
    		int answer = 0;

    		
    		while(!qu.isEmpty() && qu.peek() + speeds[idx]*day >=100){
    			answer++;
    			idx++;
    			qu.poll();

    		}
    		
    		if(answer != 0)
    			list.add(answer);
    		
    	}//while
    	
    	return list.stream().mapToInt(i->i).toArray();
    }


후기 (30min)

몇번 풀어봤던 문제임에도 불구하고 30분이나 걸렸다…!

그래도 전에는 linkedlist로 풀거나 배열로 풀었었는데 이번에는 큐로 풀어낼 수 있었다!!

또한 day의 활용을 어떻게 하냐에 따라 문제를 어떻게 풀어갈 수 있는지에 대해서도 다시 한번 생각해볼 수 있었다


tip

  1. while 문에 조건을 두개 걸어줄 때, 조건 1이 충족되어야 조건2로 넘어가기 때문에
  2. while(조건1 && 조건2)로 걸지 while(조건2 && 조건1)로 둘지 잘 생각해 줘야한다!


Read More

[백준] Dfs와 Bfs (java) Dfs_Bfs

2020-01-22

Dfs와 Bfs (백준 > 1260 > Dfs_Bfs)

문제 링크

문제설명

그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.

입력

첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 양방향이다.

출력

첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다. V부터 방문된 점을 순서대로 출력하면 된다.

예제 입력 1

4 5 1
1 2
1 3
1 4
2 4
3 4

예제 출력 1

1 2 4 3
1 2 3 4


풀이

package Dfs_Bfs;

import java.util.*;

public class beak_DfsBfs {
	
	public static void dfs(int arr[][], boolean check[], int v) {
		check[v] = true;
		
		System.out.print(v + " ");
		
		for(int i=1;i<arr.length;i++) {
				if(i==v)
					continue;
				
				if(arr[v][i] == 1 && check[i] == false) {
					//1. check[i] = true; 두번 걸어주면 안된다
					dfs(arr, check, i);
				}
		}//for
		
	}
	
	public static void bfs(int arr[][], int v) {
		Queue<Integer> qu = new LinkedList<Integer>();
		boolean check[] = new boolean[arr.length+1]; // false로 초기화
		
		qu.offer(v);
		check[v] = true;
		
		while(!qu.isEmpty()) {
			int x = qu.poll();
			
			System.out.print(x + " ");
			
			for(int i=1;i<arr.length; i++) {
				if(i == x)
					continue;

				if(arr[x][i] == 1 && check[i]== false) {
					qu.offer(i);
					check[i] = true;
				}
			}//for
			
		}//while
	}
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt(); // n*n 행렬
		int m = sc.nextInt(); //몇개의 간선이 연결되어 있는지
		int v = sc.nextInt(); //몇번째 행부터 시작할건지
		
		int arr[][] = new int[n+1][n+1];
		
        //2
		for(int i=0; i<m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			arr[a][b]=1;
			arr[b][a]=1;
		}
			
		boolean check[] = new boolean[arr.length+1]; // false로 초기화
		
		dfs(arr, check, v);
		System.out.println("");
		bfs(arr, v);
	}
}


후기 (1h)

dfs, bfs를 몇번을 풀었는데 매번 까먹어… 뭘 사용해서 풀었었는지 stack이었는지 queue였는지 재귀를 사용했는지 안했는지… 꼼꼼하게 기억해놨다가 dfs, bfs 사용하는 문제에 적용하자!

  1. dfs 조건 걸어줄 때 check[]=true를 어디에 걸지!
  2. 또 입력을 받을때, arr[a][b] 와 arr[b][a] 에 다 1 을 넣어주지 않아서 생겼던 오류까지!


tip

  1. DFS - Stack을 사용한다 - 재귀를 이용한다 - 따로 기저조건이 없다
  2. BFS - Queue를 사용한다 - for를 이용한다 (재귀 x) - while(!queue.isEmpty())를 잊지 말자!


Read More

[프로그래머스] 가장 큰 정사각형 찾기 (java) Dynamic_Programming

2020-01-21

가장 큰 정사각형 찾기 (programers > lev2 > Dynamic_Programming)

문제 링크

문제설명

1와 0로 채워진 표(board)가 있습니다. 표 1칸은 1 x 1 의 정사각형으로 이루어져 있습니다. 표에서 1로 이루어진 가장 큰 정사각형을 찾아 넓이를 return 하는 solution 함수를 완성해 주세요. (단, 정사각형이란 축에 평행한 정사각형을 말합니다.)

예를 들어

1 2 3 4
0 1 1 1
1 1 1 1
1 1 1 1
0 0 1 0

가 있다면 가장 큰 정사각형은

1 2 3 4
0 1 1 1
1 1 1 1
1 1 1 1
0 0 1 0

가 되며 넓이는 9가 되므로 9를 반환해 주면 됩니다.

제한사항
  • 표(board)는 2차원 배열로 주어집니다.
  • 표(board)의 행(row)의 크기 : 1,000 이하의 자연수
  • 표(board)의 열(column)의 크기 : 1,000 이하의 자연수
  • 표(board)의 값은 1또는 0으로만 이루어져 있습니다.

입출력 예
board answer
[[0,1,1,1],[1,1,1,1],[1,1,1,1],[0,0,1,0]] 9
[[0,0,1,1],[1,1,1,1]] 4
입출력 예 설명

입출력 예 #1 위의 예시와 같습니다.

입출력 예 #2 | 0 | 0 | 1 | 1 | | 1 | 1 | 1 | 1 | 로 가장 큰 정사각형의 넓이는 4가 되므로 4를 return합니다.


풀이

    static public int solution(int board[][]){
        int arr[][] = new int[board.length+1][board[0].length+1];
    	int answer = 0;
        
    	for(int i=1;i<arr.length; i++) {
    		for(int j=1; j<arr[0].length; j++){
    			if(board[i-1][j-1] == 1)
    				arr[i][j] = 1;
    		}
    	}
    	
        for(int i=1; i<arr.length; i++) {
        	for(int j=1; j<arr[0].length; j++) {
        		if(arr[i][j]==1) {
        			int min = Math.min(arr[i-1][j], Math.min(arr[i][j-1], arr[i-1][j-1]));
        			arr[i][j] = min+1;
        			answer = Math.max(answer, arr[i][j]);
        		}
        	}	
        }
        
        return answer * answer;
    }


후기 (1h 30min)

처음 생각한대로 풀었더니 효율성은 0%에 문제도 몇개만 맞았다..

답을 찾아보니 DP문제였고, 세곳이 1이면서 현재위치도 1인경우에만 한변이 min+1 인 정사각형의 값이 된다!!

  • 처음 생각한 방식
static public int doRight(int b[][], int i, int j) {
	int r=0;
	for(int k = j; k<b[0].length; k++) {
		if(b[i][k] == 1)
			r++;
		else
			break;
	}

	return r;
}

static public int doDown(int b[][],int i, int j){
	int d=1;
	for(int k = i; k<b.length; k++) {
		if(b[k][j] == 1)
			d++;
		else
			break;
	}		
	
	return d;
}

static public int solution(int board[][]){
    //board의 각 값마다 Point r과 d 생성
    int answer = 0;
    
    for(int i=0;i<board.length; i++) {
    	for(int j=0;j<board[0].length; j++) {
    		if(board[i][j] == 0)
    			continue;
    		
    		int right = doRight(board,i,j);
    		int down = doDown(board,i,j);
    		
        	if(right == down)
        		answer = Math.max(answer, right*down);
    	}
    	
    }
    
    return answer;
}



tip

  1. DP 문제 너무 어렵다…
  2. 생각해내는 사람들 천재같아…


Read More