[백준] 1로 만들기 (java) Dynamic_programming

2020-02-11

1로 만들기 (백준> 1463> Dynamic_programming)

문제 링크

문제설명

정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지 이다.

  1. X가 3으로 나누어 떨어지면, 3으로 나눈다.
  2. X가 2로 나누어 떨어지면, 2로 나눈다.
  3. 1을 뺀다.

정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.

입력

첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.

출력

첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.

예제 입력 1

2

예제 출력 1

1

예제 입력 2

10

예제 출력 2

3


풀이

package Dynamic_programming;

import java.util.*;

public class beak_1로만들기 {

	//50 min
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		
		int dp[] = new int[n+1];
		Queue<Integer> qu = new LinkedList<>();
		qu.add(n);
		
		while(!qu.isEmpty()) {
			n = qu.poll();
			
			if(n == 1) {
				System.out.println( dp[1] );
				break;
			}
			
			
			if(n%3==0 && dp[n/3]==0) { //dp[n]==0일떄 방문해야 최소, 방문했던곳은 안간다 -> n은 이미 방문했던 곳이라 값이 있고 n/2, n/3을 확인해야한
				int k = n/3;
				dp[k] = dp[n] +1;
				qu.offer(k);
			}
			if(n%2==0 && dp[n/2]==0) {
				int k = n/2;
				dp[k] = dp[n] +1;
				qu.offer(k);
			}
			if(dp[n-1]==0) { //n 아니고  n-1이잖아 조건 잘 봐줘!
				int k = n-1;
				dp[k] = dp[n] +1;
				qu.offer(k);
			}
			
			
		}//while
		
	}
}


후기 (50min)

어제 풀었던 대로 갔던 곳의 횟수를 담는 배열을 만들어 풀었다. 막판에 조건 하나를 잘못 써줘서 안돌았는데 그 부분 조심하고 복습 꼭 하기


tip

  1. 늘 실패하는건 컴퓨터 탓이 아니라 내 탓!^^ 조건 하나하나 잘 보자


Read More

[프로그래머스] 캐시 (java) Queue

2020-02-11

캐시(programers > lev2 > Stack_Queue)

문제 링크

문제설명

지도개발팀에서 근무하는 제이지는 지도에서 도시 이름을 검색하면 해당 도시와 관련된 맛집 게시물들을 데이터베이스에서 읽어 보여주는 서비스를 개발하고 있다. 이 프로그램의 테스팅 업무를 담당하고 있는 어피치는 서비스를 오픈하기 전 각 로직에 대한 성능 측정을 수행하였는데, 제이지가 작성한 부분 중 데이터베이스에서 게시물을 가져오는 부분의 실행시간이 너무 오래 걸린다는 것을 알게 되었다. 어피치는 제이지에게 해당 로직을 개선하라고 닦달하기 시작하였고, 제이지는 DB 캐시를 적용하여 성능 개선을 시도하고 있지만 캐시 크기를 얼마로 해야 효율적인지 몰라 난감한 상황이다.

어피치에게 시달리는 제이지를 도와, DB 캐시를 적용할 때 캐시 크기에 따른 실행시간 측정 프로그램을 작성하시오.

입력 형식

  • 캐시 크기(cacheSize)와 도시이름 배열(cities)을 입력받는다.
  • cacheSize는 정수이며, 범위는 0 ≦ cacheSize ≦ 30 이다.
  • cities는 도시 이름으로 이뤄진 문자열 배열로, 최대 도시 수는 100,000개이다.
  • 각 도시 이름은 공백, 숫자, 특수문자 등이 없는 영문자로 구성되며, 대소문자 구분을 하지 않는다. 도시 이름은 최대 20자로 이루어져 있다.

출력 형식

  • 입력된 도시이름 배열을 순서대로 처리할 때, 총 실행시간을 출력한다.

조건

  • 캐시 교체 알고리즘은 LRU(Least Recently Used)를 사용한다.
  • cache hit일 경우 실행시간은 1이다.
  • cache miss일 경우 실행시간은 5이다.

입출력 예제

캐시크기(cacheSize) 도시이름(cities) 실행시간
3 [Jeju, Pangyo, Seoul, NewYork, LA, Jeju, Pangyo, Seoul, NewYork, LA] 50
3 [Jeju, Pangyo, Seoul, Jeju, Pangyo, Seoul, Jeju, Pangyo, Seoul] 21
2 [Jeju, Pangyo, Seoul, NewYork, LA, SanFrancisco, Seoul, Rome, Paris, Jeju, NewYork, Rome] 60
5 [Jeju, Pangyo, Seoul, NewYork, LA, SanFrancisco, Seoul, Rome, Paris, Jeju, NewYork, Rome] 52
2 [Jeju, Pangyo, NewYork, newyork] 16
0 [Jeju, Pangyo, Seoul, NewYork, LA] 25


풀이

package Stack_Queue;

import java.util.*;

public class prog_2_캐시 {

	//은근 잔 조건들이 많네...; 40min
	  static public int solution(int cacheSize, String[] cities) {
	      int answer = 0;
	      LinkedList<String> qu = new LinkedList<String>();
	      
	      String real[] = new String[cities.length];
	      
	      for(int i=0;i<cities.length; i++)
	    	  real[i] = cities[i].toUpperCase();
	      
	      if(cacheSize == 0)
	    	  return cities.length * 5;
	      
	      for(int i=0;i<cities.length; i++) {
	    	  String an = real[i];
	    	  System.out.println(an);
	    	  
	    	  if(qu.size() < cacheSize) {
	    		  if(qu.contains(an)) {
	    			  int idx = qu.indexOf(an);// 위치 찾아서
	    			  qu.remove(idx); // 제거하고
	    			  qu.add(an); //위에 새로 추가
	    			  
	    			  answer = answer+1;
	    		  }
	    		  else {
	    			  qu.add(an); //위에 새로 추가 
	    			  answer = answer +5;
	    		  }
	    	  }
	    	  
	    	  else if( qu.size() >= cacheSize){
	    		  if(qu.contains(an)) {
	    			  int idx = qu.indexOf(an);// 위치 찾아서
	    			  qu.remove(idx); // 제거하고
	    			  qu.add(an); //위에 새로 추가
	    			  
	    			  answer = answer+1;
	    		  }
	    		  else {
	    			  qu.remove(0); //맨 앞이 제일 오래된 데이터
	    			  qu.add(an); //위에 새로 추가 
	    			  answer = answer +5;
	    		  }	    		  
	    	  }
	    	  
	      }//for
	      
	      return answer;
	  }
	  
	  public static void main(String[] args) {
		String s[] = {"Jeju", "Pangyo", "Seoul", "NewYork", "LA"};
		System.out.println(solution(3, s));
	  }
	  
}


후기 (40min)

다 풀었다고 생각하고 코드를 돌렸는데, 여러번 몇개가 실패로 뜨길래 뭔가 봤더니 대소문자 구분하지않는다는 조건, 또 (qu.size <cacheSize)가 아닌 (qu.size < num=0)이런식으로 해놔서 에러가 났었다.

조건 찾아 고치는데만 십분 잡아먹은 것 같으니 앞으로는 조심!


tip

  1. 조건들을 꼼꼼하게 파악한 후 문제를 풀도록 하자


Read More

[프로그래머스] 멀리뛰기 (java) Dynamic_Programming

2020-02-10

멀리뛰기 (programers > lev3 > Dynamic_Programming)

문제 링크

문제설명

효진이는 멀리 뛰기를 연습하고 있습니다. 효진이는 한번에 1칸, 또는 2칸을 뛸 수 있습니다. 칸이 총 4개 있을 때, 효진이는 (1칸, 1칸, 1칸, 1칸) (1칸, 2칸, 1칸) (1칸, 1칸, 2칸) (2칸, 1칸, 1칸) (2칸, 2칸) 의 5가지 방법으로 맨 끝 칸에 도달할 수 있습니다. 멀리뛰기에 사용될 칸의 수 n이 주어질 때, 효진이가 끝에 도달하는 방법이 몇 가지인지 알아내, 여기에 1234567를 나눈 나머지를 리턴하는 함수, solution을 완성하세요. 예를 들어 4가 입력된다면, 5를 return하면 됩니다.

제한 사항
  • n은 1 이상, 2000 이하인 정수입니다.
입출력 예
n result
4 5
3 3
입출력 예 설명

입출력 예 #1 위에서 설명한 내용과 같습니다.

입출력 예 #2 (2칸, 1칸) (1칸, 2칸) (1칸, 1칸, 1칸) 총 3가지 방법으로 멀리 뛸 수 있습니다.


풀이

package Dynamic_programming;

public class prog_3_멀리뛰기 {

	static public long solution(int n) {
		      
		      long dp[] = new long[2001];
		      dp[1] = 1;
		      dp[2] = 2;
		      
		      for(int i=3;i<=2000; i++)
		    	  dp[i] = (dp[i-1] + dp[i-2]) %1234567;
		      
		      return dp[n];
	  }
	
	public static void main(String[] args) {
		System.out.println(solution(2000));
	}
}


후기 (10min)

공교롭게도 1,2,3 더하기 를 풀자마자 1,2 를 이용하는 문제가 똑같이 나왔다!

아까는 123을 이용해 풀었다면 이번에는 12를 이용하는 문제였고 다른 부분은 똑같다고 할 수 있다


tip

  1. 비슷한 문제를 반복해서 풀면 어려워 보이는 문제도 쉽게 풀 수있다는 걸 다시 하번 깨달았다.
  2. for문을 2000번밖에 돌지 않아서 숫자가 크지않을 것이라고 생각했는데 생각보다 숫자가 컸다!
Read More

[프로그래머스] 이중우선순위큐 (java) Queue

2020-02-10

이중우선순위큐 (programers > lev3 > Stack_Queue)

문제 링크

문제설명

이중 우선순위 큐는 다음 연산을 할 수 있는 자료구조를 말합니다.

명령어 수신 탑(높이)
I 숫자 큐에 주어진 숫자를 삽입합니다.
D 1 큐에서 최댓값을 삭제합니다.
D -1 큐에서 최솟값을 삭제합니다.

이중 우선순위 큐가 할 연산 operations가 매개변수로 주어질 때, 모든 연산을 처리한 후 큐가 비어있으면 [0,0] 비어있지 않으면 [최댓값, 최솟값]을 return 하도록 solution 함수를 구현해주세요.

제한사항
  • operations는 길이가 1 이상 1,000,000 이하인 문자열 배열입니다.
  • operations의 원소는 큐가 수행할 연산을 나타냅니다.
    • 원소는 “명령어 데이터” 형식으로 주어집니다.- 최댓값/최솟값을 삭제하는 연산에서 최댓값/최솟값이 둘 이상인 경우, 하나만 삭제합니다.
  • 빈 큐에 데이터를 삭제하라는 연산이 주어질 경우, 해당 연산은 무시합니다.
입출력 예
operations return
[I 16,D 1] [0,0]
[I 7,I 5,I -5,D -1] [7,5]
입출력 예 설명

16을 삽입 후 최댓값을 삭제합니다. 비어있으므로 [0,0]을 반환합니다. 7,5,-5를 삽입 후 최솟값을 삭제합니다. 최대값 7, 최소값 5를 반환합니다.


풀이

package Stack_Queue;

import java.util.*;

public class prog_3_이중우선순위큐 {

    static public int[] solution(String[] operations) {
        LinkedList<Integer> realqu = new LinkedList<Integer>();
        int answer[] = {0,0};
        
        for(int i=0;i<operations.length; i++) {
            Collections.sort(realqu,Collections.reverseOrder());
        	String a[] = operations[i].split(" ");
        	
        	System.out.println(realqu);
        	
        	if(a[0].equals("I")) {
        		realqu.add(Integer.parseInt(a[1]));
        	}
        	
        	if(a[0].equals("D") && a[1].equals("1")) {
        		if(realqu.isEmpty())
        			continue;
        		
        		realqu.remove(0);
        	}
        	
        	if(a[0].equals("D") && a[1].equals("-1")) {
        		if(realqu.isEmpty())
        			continue;
        		
           		realqu.remove(realqu.size()-1);
        	}
        	
        }
        
        //매번 reverse 해줘야 한다는 점 잊지말자!
        Collections.sort(realqu,Collections.reverseOrder());
        
        if(realqu.isEmpty()) {
        	answer[0] = 0;
        	answer[1] = 0;
        }
        else {
        	answer[0] = realqu.get(0);
        	answer[1] = realqu.get(realqu.size()-1);
        }
        
        return answer;
    }
	
    
	public static void main(String[] args) {
		String a[] = {"I -45", "I 653", "D 1", "I -642", "I 45", "I 97", "D 1", "D -1", "I 333"};
		solution(a);
	}
}


후기 (40min)

queue와 stack을 동시에 사용해야 하나 처음에는 생각했지만, 꼼수로 LinkedList를 만들고 reverse를 통해 오름차순으로 매번 정렬해주어 맨 앞과 뒤를 꺼내는 방식으로 문제를 풀었다.


tip

  1. reverse를 매번 해줘야 정렬이 되고, 마지막에 for문을 빠져나와서도 정렬을 해주는 부분에서 헷갈렸지만 이내 발견했다!
Read More

[백준] 1,2,3 더하기 (java) Dynamic_Programming

2020-02-10

1,2,3 더하기 (백준> 1697 > Dynamic_Programming)

문제 링크

문제설명

정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다.

  • 1+1+1+1
  • 1+1+2
  • 1+2+1
  • 2+1+1
  • 2+2
  • 1+3
  • 3+1

정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 n이 주어진다. n은 양수이며 11보다 작다.

출력

각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 출력한다.

예제 입력 1

3
4
7
10

예제 출력 1

7
44
274


풀이

package Dynamic_programming;

public class beak_123더하기 {

	public static void main(String[] args) {
		int arr[] = new int[12];
		
		arr[0] = 0;
		arr[1] = 1;
		arr[2] = 2;
		arr[3] = 4;
		
		for(int i=4;i<=11;i++) 
			arr[i] = arr[i-1] + arr[i-2] + arr[i-3];
		
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt();
		for(int i=0;i<n;i++) {
			int a = sc.nextInt();
			System.out.println(arr[a]);
		}
		
	}
}

후기 (1h)

dp문제는 항상 수식 세우는 게 가장 어렵다… 아래 링크를 참고했고, 까먹지 않도록 반복!


tip

  1. 1을 기준으로 두고 k를 만드는 경우의 수 + 2를 기준으로 두고 + 3을 기준으로 두면 -> 4가 가질 수 있는 경우의 수가 신기하게 나왔다…!

https://nhs0912.tistory.com/62

Read More