복습 6

2020-04-17

복습 6

프로그래머스 스킬체크 테스트 2

  1. 트럭(Queue)

    불과 그제풀고, 어제 복습했던 문제인데도 10분컷을 하지 못했다…

    일단 조건은 제대로 맞추었으나!

    트럭을 더 적재하는 부분의 조건에서 idx를 넘어가지 않는다는 조건을 걸어주지않아서… 헤맴!

                    if(idx<truck_weights.length){
                        int w = 0;
                        for(int i=0; i<trk.size(); i++){
                            w += trk.get(i).wei;                    
                        }
                       
                        if(w + truck_weights[idx] <=weight){
                        trk.add(new truck(truck_weights[idx],1));
                        idx++;
                        }
                    }
    
  2. 조이스틱 (Greedy)

    참으로 오랜만인 문제!

    • 제일 오래걸리는 건 끝까지 다 가는 것! or
    • 현재위치에서 다시 0위치로가서 (i+i) , 맨뒤로가서 (len), A를 만나기 직전까지!(next)
    • 따라서 i+i+len-next

    또, 맨끝까지가서는 비교할 필요가 없으니 for문은 len-1까지만 돌아준다!

    static public int solution(String name) {
            int answer = 0;
            for(int i = 0; i<name.length(); i++) {
            	if(name.charAt(i) -'A' <13)
            		answer += name.charAt(i)- 'A';
            	else
            		answer += 'Z' - name.charAt(i)+1;
            }
               
            int min_move = name.length()-1;
            for(int i=0; i<name.length()-1; i++) {
            	int next = i+1;
               	
            	while(next<name.length() && name.charAt(next) == 'A')
            		next++;
               
            	min_move = Math.min(min_move, (i+name.length()) + i-next);	
            }
            return answer + min_move;
    }
    
Read More

[백준] 괄호의 값 (java) Stack

2020-04-16

괄호의 값 (백준> Stack_Queue)

문제 링크

문제설명

4개의 기호 ‘(’, ‘)’, ‘[’, ‘]’를 이용해서 만들어지는 괄호열 중에서 올바른 괄호열이란 다음과 같이 정의된다.

  1. 한 쌍의 괄호로만 이루어진 ‘()’와 ‘[]’는 올바른 괄호열이다.
  2. 만일 X가 올바른 괄호열이면 ‘(X)’이나 ‘[X]’도 모두 올바른 괄호열이 된다.
  3. X와 Y 모두 올바른 괄호열이라면 이들을 결합한 XY도 올바른 괄호열이 된다.

예를 들어 ‘(()[[]])’나 ‘(())[][]’ 는 올바른 괄호열이지만 ‘([)]’ 나 ‘(()()[]’ 은 모두 올바른 괄호열이 아니다. 우리는 어떤 올바른 괄호열 X에 대하여 그 괄호열의 값(괄호값)을 아래와 같이 정의하고 값(X)로 표시한다.

  1. ‘()’ 인 괄호열의 값은 2이다.
  2. ‘[]’ 인 괄호열의 값은 3이다.
  3. ‘(X)’ 의 괄호값은 2×값(X) 으로 계산된다.
  4. ‘[X]’ 의 괄호값은 3×값(X) 으로 계산된다.
  5. 올바른 괄호열 X와 Y가 결합된 XY의 괄호값은 값(XY)= 값(X)+값(Y) 로 계산된다.

예를 들어 ‘(()[[]])([])’ 의 괄호값을 구해보자. ‘()[[]]’ 의 괄호값이 2 + 3×3=11 이므로 ‘(()[[ ]])’의 괄호값은 2×11=22 이다. 그리고 ‘([])’의 값은 2×3=6 이므로 전체 괄호열의 값은 22 + 6 = 28 이다.

여러분이 풀어야 할 문제는 주어진 괄호열을 읽고 그 괄호값을 앞에서 정의한대로 계산하여 출력하는 것이다.

입력

첫째 줄에 괄호열을 나타내는 문자열(스트링)이 주어진다. 단 그 길이는 1 이상, 30 이하이다.

출력

첫째 줄에 그 괄호열의 값을 나타내는 정수를 출력한다. 만일 입력이 올바르지 못한 괄호열이면 반드시 0을 출력해야 한다.

예제 입력 1 복사

(()[[]])([])

예제 출력 1 복사

28


풀이

package Stack_Queue;

import java.util.*;

public class beak_괄호의값 {

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		
		String s = sc.nextLine();
		Stack<Character> stk = new Stack<>();
		
		int mul = 1; int result = 0;
		
		for(int i=0; i<s.length(); i++) {
			switch(s.charAt(i)) {
			
			case '(':
				stk.push('(');
				mul = mul*2;
				break;
				
			case '[':
				stk.push('[');
				mul = mul*3;
				break;
				
			case ')':
				//반드시 앞에 (가 존재해야한다!
                 //이 경우는 peek에 [가 들어있는 경우이므로 result = 0;
				if(stk.isEmpty() || stk.peek() !='(') {
					result = 0;
					break;
				}
				
				//내 바로앞이 (일때만 result에 넣어준다
				if(s.charAt(i-1) == '(')
					result = result + mul;
				
				//위의 경우 || s.charAt(i-1)이 '('가 아닌경우
				stk.pop();
				mul = mul/2;
				break;
				
			case ']':
				//반드시 앞에 [가 존재해야한다!
                 //이 경우는 peek에 (가 들어있는 경우이므로 result = 0;
				if(stk.isEmpty() || stk.peek() !='[') {
					result = 0;
					break;
				}

				//내 바로앞이 [일때만 result에 넣어준다
				if(s.charAt(i-1) == '[')
					result = result+mul;	

				//위의 경우 || s.charAt(i-1)이 '['가 아닌경우
				stk.pop();
				mul= mul/3;
				break;
				
			}//switch
		}
		
		if(!stk.isEmpty())
			System.out.println(0);
		else
			System.out.println(result);
		
	}
}

//참고
//https://blog.naver.com/PostView.nhn?blogId=yongyos&logNo=221454435252

후기 (1h)

쉬운 문젠줄 알았다가 깜짝 놀람…

  1. (, [일 때는 스택에 넣어주면서 && 무조건 mulx2 , mulx3 을 해준다
  2. ),] 위에서 무조건 넣어주었으니 ), ]일 때는 mul/2, mul/3을 해주되,
    1. 바로 앞이 맞는 짝일 때만 result = result + mul을 해준다.
    2. 또, pop해야 하는 상황인데 스택이 비어있거나, 스택의 peek가 맞는 짝이 아닐 때는 result를 0으로 만든다.
      • 스택이 비어있을때 result=0을 만들어주고 나가는건 잘못된 짝인 경우인거고
      • peek가 맞는 짝이 아닐때 또한, 잘못된 경우이므로 result = 0을 만들어 주어야 한다


오우.. 너무 어렵… 따져줘야할 조건들이 굉장히 까다롭다!

Read More

[백준] 스택 수열 (java) Stack

2020-04-14

스택 수열 (백준> Stack_Queue)

문제 링크

문제설명

스택 (stack)은 기본적인 자료구조 중 하나로, 컴퓨터 프로그램을 작성할 때 자주 이용되는 개념이다. 스택은 자료를 넣는 (push) 입구와 자료를 뽑는 (pop) 입구가 같아 제일 나중에 들어간 자료가 제일 먼저 나오는 (LIFO, Last in First out) 특성을 가지고 있다.

1부터 n까지의 수를 스택에 넣었다가 뽑아 늘어놓음으로써, 하나의 수열을 만들 수 있다. 이때, 스택에 push하는 순서는 반드시 오름차순을 지키도록 한다고 하자. 임의의 수열이 주어졌을 때 스택을 이용해 그 수열을 만들 수 있는지 없는지, 있다면 어떤 순서로 push와 pop 연산을 수행해야 하는지를 알아낼 수 있다. 이를 계산하는 프로그램을 작성하라.

입력

첫 줄에 n (1 ≤ n ≤ 100,000)이 주어진다. 둘째 줄부터 n개의 줄에는 수열을 이루는 1이상 n이하의 정수가 하나씩 순서대로 주어진다. 물론 같은 정수가 두 번 나오는 일은 없다.

출력

입력된 수열을 만들기 위해 필요한 연산을 한 줄에 한 개씩 출력한다. push연산은 +로, pop 연산은 -로 표현하도록 한다. 불가능한 경우 NO를 출력한다.

예제 입력 1 복사

8
4
3
6
8
7
5
2
1

예제 출력 1 복사

+
+
+
+
-
-
+
+
-
+
+
-
-
-
-
-

예제 입력 2 복사

5
1
2
5
3
4

예제 출력 2 복사

NO


풀이

package Stack_Queue;

import java.util.*;

public class beak_스택수열 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt();
		Queue<Integer> qu = new LinkedList<>();
		Stack<Integer> stk = new Stack<>();
		StringBuilder sb = new StringBuilder();
		
		for(int i=0; i<n; i++)
			qu.add(sc.nextInt());
		
		int x = 1;
		
		while(x<=n) {
				//일단 넣고
				stk.add(x);
				sb.append("+\n");
				while(!stk.isEmpty()&& !qu.isEmpty()&&stk.peek().intValue() == qu.peek().intValue()) {
						stk.pop();
						qu.poll();
						sb.append("-\n");
				}//while

			x++;
		}//while
		
		if(!stk.isEmpty())
			System.out.println("NO");
		else
			System.out.println(sb.toString());
			
	}
}

후기 (1h)

string으로 문제풀고 계속 30퍼쯤에서 실패 뜨다가 뭐지 했는데…

반례를 찾다가 두 가지를 고쳤다(알고리즘 적으로 고친건 X)

  1. LinkedList에 답을 하나씩 넣었었는데 그를 **sb.append("")**로 바꿈
  2. 또, Integer는 128 이상부터는 ==기능을 제대로 하지못한다 하여, stk.peek().intValue() == qu.peek().intValue()로 바꿈

그랬더니 놀랍게도 통!과!

Read More

[프로그래머스] 다리를 지나는 트럭 (java) Queue

2020-04-14

다리를 지나는 트럭 (프로그래머스> Stack_Queue)

문제 링크

문제설명

트럭 여러 대가 강을 가로지르는 일 차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다. 트럭은 1초에 1만큼 움직이며, 다리 길이는 bridge_length이고 다리는 무게 weight까지 견딥니다. ※ 트럭이 다리에 완전히 오르지 않은 경우, 이 트럭의 무게는 고려하지 않습니다.

예를 들어, 길이가 2이고 10kg 무게를 견디는 다리가 있습니다. 무게가 [7, 4, 5, 6]kg인 트럭이 순서대로 최단 시간 안에 다리를 건너려면 다음과 같이 건너야 합니다.

경과 시간 다리를 지난 트럭 다리를 건너는 트럭 대기 트럭
0 [] [] [7,4,5,6]
1~2 [] [7] [4,5,6]
3 [7] [4] [5,6]
4 [7] [4,5] [6]
5 [7,4] [5] [6]
6~7 [7,4,5] [6] []
8 [7,4,5,6] [] []

따라서, 모든 트럭이 다리를 지나려면 최소 8초가 걸립니다.

solution 함수의 매개변수로 다리 길이 bridge_length, 다리가 견딜 수 있는 무게 weight, 트럭별 무게 truck_weights가 주어집니다. 이때 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 return 하도록 solution 함수를 완성하세요.

제한 조건
  • bridge_length는 1 이상 10,000 이하입니다.
  • weight는 1 이상 10,000 이하입니다.
  • truck_weights의 길이는 1 이상 10,000 이하입니다.
  • 모든 트럭의 무게는 1 이상 weight 이하입니다.
입출력 예
bridge_length weight truck_weights return
2 10 [7,4,5,6] 8
100 100 [10] 101
100 100 [10,10,10,10,10,10,10,10,10,10] 110


풀이

package Stack_Queue;

import java.util.*;

public class prog_2_re_다리를지나는트럭 {
	static class Pos{
		int size;
		int on_bri;
		
		Pos(int size, int on_bri){
			this.size = size;
			this.on_bri = on_bri;
		}
	}
	
    static public int solution(int bridge_length, int weight, int[] truck_weights) {
    	
    	LinkedList<Pos> trk = new LinkedList<>();
    	int size = truck_weights.length;
    	
    	//일단 넣고 시작
    	trk.add(new Pos(truck_weights[0],1)); //0들어가고 1번째르 건너고있다
    	int idx = 1; //다음 트럭의 위치
    	int second = 1; // 하나 쌓았으니까 1초 지나감
    	size = size-1;
    	
    	while(size!=-1) {
    		//trk가 안비어있으면 
    		if(!trk.isEmpty()) {
    			//한칸씩 다 움직여주기
    			for(int i=0; i<trk.size(); i++)
    				trk.set(i, new Pos(trk.get(i).size,trk.get(i).on_bri+1));
    			
    			//그리고 다음거 들어올 수 있나 보기
    			if(idx<truck_weights.length) {
    				int wei = 0;
    				for(int i=0; i<trk.size(); i++)
    					wei += trk.get(i).size;
    				
    				//지금 있는거 wei에 다음 weight 추가한게 적재 가능하면
    				if(wei+truck_weights[idx] <= weight) {
    					trk.add(new Pos(truck_weights[idx],1));
    					idx++;
    				}
    			}
    			
    			//맨 처음게 나갈 시간이면 빼주기
    			if(trk.get(0).on_bri == bridge_length) {
    				trk.remove();
    				size = size-1;
    			}
    			
    		}
    		//트럭이 비었으면 무조건 한개 적재!
    		else {
    			trk.add(new Pos(truck_weights[idx],1));
    			idx++;
    		}

    		//시간 증가시키기
    		second++;
    	}//while

    	return second+1;
    }
    
    public static void main(String[] args) {
		int s[] = {10};
    	System.out.println(solution(100,100,s));
	}
}

후기 (40min)

어려운 문제라기 보다는.. 조건을 어떻게 걸어줄지를 더 생각해야하는 문제!

  1. 일단 첫번째 트럭을 stk에 넣고
  2. idx는 다음 트럭의 위치를 가리킨다
  3. second는 현재 초를 말한다
  4. size는 전체 트럭의 크기
  5. 따라서 첫번째 트럭을 넣었으니 idx = 1, second = 1, size = size-1



이 루트를 따르면 된다!!

  1. size 전체 트럭의 크기가 0이될 때까지 돈다

  2. trk(큐)이 안비어 있다면
    1. 안에 있는거 전부 한칸씩 움직이기
    2. 다음거 들어올 수 있나 확인 (무조건 1개만 들어옴)
      1. 확인 방법은, 지금있는 wei에 다음 [idx].wei가 가능한지?
      2. 가능하면 큐에 추가
    3. 맨 앞에있는 트럭이 나갈 수 있는지 확인 (무조건 1개만 나감)
      1. 나갈 수 있다면 큐에서 제거
      2. size도 -1
  3. trk(큐)이 비어있다면
    1. 무조건 한개 적재한다
  4. 시간 증가시킨다
Read More

[프로그래머스] 디스크 컨트롤러 (java) Heap

2020-04-14

디스크 컨트롤러 (프로그래머스> Heap)

문제 링크

문제설명

하드디스크는 한 번에 하나의 작업만 수행할 수 있습니다. 디스크 컨트롤러를 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 요청이 들어온 순서대로 처리하는 것입니다.

예를들어

- 0ms 시점에 3ms가 소요되는 A작업 요청
- 1ms 시점에 9ms가 소요되는 B작업 요청
- 2ms 시점에 6ms가 소요되는 C작업 요청

와 같은 요청이 들어왔습니다. 이를 그림으로 표현하면 아래와 같습니다. Screen Shot 2018-09-13 at 6.34.58 PM.png

한 번에 하나의 요청만을 수행할 수 있기 때문에 각각의 작업을 요청받은 순서대로 처리하면 다음과 같이 처리 됩니다. Screen Shot 2018-09-13 at 6.38.52 PM.png

- A: 3ms 시점에 작업 완료 (요청에서 종료까지 : 3ms)
- B: 1ms부터 대기하다가, 3ms 시점에 작업을 시작해서 12ms 시점에 작업 완료(요청에서 종료까지 : 11ms)
- C: 2ms부터 대기하다가, 12ms 시점에 작업을 시작해서 18ms 시점에 작업 완료(요청에서 종료까지 : 16ms)

이 때 각 작업의 요청부터 종료까지 걸린 시간의 평균은 10ms(= (3 + 11 + 16) / 3)가 됩니다.

하지만 A → C → B 순서대로 처리하면 Screen Shot 2018-09-13 at 6.41.42 PM.png

- A: 3ms 시점에 작업 완료(요청에서 종료까지 : 3ms)
- C: 2ms부터 대기하다가, 3ms 시점에 작업을 시작해서 9ms 시점에 작업 완료(요청에서 종료까지 : 7ms)
- B: 1ms부터 대기하다가, 9ms 시점에 작업을 시작해서 18ms 시점에 작업 완료(요청에서 종료까지 : 17ms)

이렇게 A → C → B의 순서로 처리하면 각 작업의 요청부터 종료까지 걸린 시간의 평균은 9ms(= (3 + 7 + 17) / 3)가 됩니다.

각 작업에 대해 [작업이 요청되는 시점, 작업의 소요시간]을 담은 2차원 배열 jobs가 매개변수로 주어질 때, 작업의 요청부터 종료까지 걸린 시간의 평균을 가장 줄이는 방법으로 처리하면 평균이 얼마가 되는지 return 하도록 solution 함수를 작성해주세요. (단, 소수점 이하의 수는 버립니다)

제한 사항
  • jobs의 길이는 1 이상 500 이하입니다.
  • jobs의 각 행은 하나의 작업에 대한 [작업이 요청되는 시점, 작업의 소요시간] 입니다.
  • 각 작업에 대해 작업이 요청되는 시간은 0 이상 1,000 이하입니다.
  • 각 작업에 대해 작업의 소요시간은 1 이상 1,000 이하입니다.
  • 하드디스크가 작업을 수행하고 있지 않을 때에는 먼저 요청이 들어온 작업부터 처리합니다.
입출력 예
jobs return
[[0, 3], [1, 9], [2, 6]] 9
입출력 예 설명

문제에 주어진 예와 같습니다.

  • 0ms 시점에 3ms 걸리는 작업 요청이 들어옵니다.
  • 1ms 시점에 9ms 걸리는 작업 요청이 들어옵니다.
  • 2ms 시점에 6ms 걸리는 작업 요청이 들어옵니다.


풀이

package Heap;

import java.util.*;

class Job implements Comparable<Job>{
	int start;
	int doing;
	
	public Job(int start, int doing) {
		this.start = start;
		this.doing = doing;
	}
	
	@Override
	public int compareTo(Job o) {
		//doing이 같을때는, 원래있던 거로 오름차순
		if(this.doing == o.doing) {
			if(this.start > o.start)
				return this.start- o.start;
			else
				return -1;
		}
		//현재 들어온 doing이 더 크면 내림차순
		else if(this.doing < o.doing)
			return -1;
		//결론 -> 현재 들어온 doing이 작으면 오름차순
		else
			return 1;
	}
	
}

public class prog_3_디스크컨트롤러 {
  static public int solution(int[][] jobs) {

      PriorityQueue<Job> pq = new PriorityQueue<>();
      List<Job> list = new ArrayList<>();
      
      //job 정렬
      for(int i=0; i<jobs.length; i++)
      	pq.add(new Job(jobs[i][0], jobs[i][1]));
      
      //list에 pq 그대로  삽입
      for(int i=0; i<jobs.length; i++)
      	list.add(pq.poll());
      
      int time = 0;
      int sum = 0;
      
      while(list.size()>0) {
      	for(int i=0; i<list.size(); i++) {
      		//시작해야하는 시간이 지금 시간 time보다 작으면 시작 가능
      		if(time>= list.get(i).start) {
      			time += list.get(i).doing;
      			sum += time- list.get(i).start; //종료시각은 끝난시간 - 시작시간
      			list.remove(i);
      			break; // 한번하면 끝내기
      		}
      		//시작시간이 다  time보다 크다면 -> disk에 안들어온 것이니 지금 시작 불가능
      		//끝까지 다 봤다면
      		if(i == list.size()-1)
      			time++;
      	}
      }
      
      return sum/jobs.length;
  }
  
}

후기 (1h)

처음에는 간단하게 뒤에거로 정렬해주기만하면 된다고 생각했지만!!

  1. 정렬은 애초에 뒤에거로 돼있으니까 list.get(i) 하면
    1. doing으로 오름차순되는 동시에
    2. 같다면 start로 오름차순되니까
    3. 덜 오래걸리는 거부터 한다
  2. 아직 안들어왔는데 time 현재시간보다 더 앞에 끝났어야 하는 애 ->먼저 해주고
  3. time은 지난시간이니까 time +=doing
  4. sum은 기다린시간부터 체크해야하니까 sum += time- list.get(i).start
  5. 또 한 번 계산했으면 다시 정렬해준다 break
  6. 끝까지 갔는데 현재 time보다 전부 크다면 작업해줄 수 있는게 없으니까 time++


굳이 클래스 안만들고 job으로 정렬해도 됐을거같은데, 그럼 매번 정렬해줘야하기때문에 간단하게

  1. Job 클래스를 만들어서 Comparable로 정렬해주고
  2. pq에 넣어서 자동으로 빼도 정렬되도록 해준다
  3. pq에 있는걸 굳이 list로 이동하는 이유는
    1. pq는 get으로 특정 idx의 값을 확인하지도 빼지도 못한다
    2. 또, 한번 pq에 넣은 채로 정렬된 상태를 유지한다
Read More