[프로그래머스] 베스트 앨범 - Fail(java) Hash

2020-04-06

베스트 앨범 (프로그래머스> Hash) fail…

문제 링크

문제설명

스트리밍 사이트에서 장르 별로 가장 많이 재생된 노래를 두 개씩 모아 베스트 앨범을 출시하려 합니다. 노래는 고유 번호로 구분하며, 노래를 수록하는 기준은 다음과 같습니다.

  1. 속한 노래가 많이 재생된 장르를 먼저 수록합니다.
  2. 장르 내에서 많이 재생된 노래를 먼저 수록합니다.
  3. 장르 내에서 재생 횟수가 같은 노래 중에서는 고유 번호가 낮은 노래를 먼저 수록합니다.

노래의 장르를 나타내는 문자열 배열 genres와 노래별 재생 횟수를 나타내는 정수 배열 plays가 주어질 때, 베스트 앨범에 들어갈 노래의 고유 번호를 순서대로 return 하도록 solution 함수를 완성하세요.

제한사항
  • genres[i]는 고유번호가 i인 노래의 장르입니다.
  • plays[i]는 고유번호가 i인 노래가 재생된 횟수입니다.
  • genres와 plays의 길이는 같으며, 이는 1 이상 10,000 이하입니다.
  • 장르 종류는 100개 미만입니다.
  • 장르에 속한 곡이 하나라면, 하나의 곡만 선택합니다.
  • 모든 장르는 재생된 횟수가 다릅니다.
입출력 예
genres plays return
[classic, pop, classic, classic, pop] [500, 600, 150, 800, 2500] [4, 1, 3, 0]
입출력 예 설명

classic 장르는 1,450회 재생되었으며, classic 노래는 다음과 같습니다.

  • 고유 번호 3: 800회 재생
  • 고유 번호 0: 500회 재생
  • 고유 번호 2: 150회 재생

pop 장르는 3,100회 재생되었으며, pop 노래는 다음과 같습니다.

  • 고유 번호 4: 2,500회 재생
  • 고유 번호 1: 600회 재생

따라서 pop 장르의 [4, 1]번 노래를 먼저, classic 장르의 [3, 0]번 노래를 그다음에 수록합니다.


풀이

package Hash;

import java.util.*;

public class prog_3_베스트엘범 {
	static class Pos{
		int song;
		int idx;
		
		Pos(int song, int idx){
			this.song = song;
			this.idx = idx;
		}
	}
	
	static public int[] calculation(LinkedList<Pos> tm) {
		int answer[][] = new int[2][2];
		boolean ck = false;
		
		for(int i=0; i<tm.size(); i++) {
			int tsong = tm.get(i).song;
			int tidx = tm.get(i).idx;
			
			
			if(answer[0][0] ==0 && answer[1][0] == 0) {
				answer[0][0] = tsong;
				answer[0][1] = tidx;
			}
			else if(answer[0][0] !=0 && answer[1][0] ==0) {
				ck = true;

				if(answer[0][0] == tsong) {
					if(answer[0][1] < tidx) {

						answer[1][0] = answer[0][0];
						answer[1][1] = answer[0][1];
						answer[0][0] = tsong;
						answer[0][1] = tidx;
					}
					else {
						answer[1][0] = tsong;
						answer[1][1] = tidx;
					}
				}
				
				else if(answer[0][0] < tsong) {
					answer[1][0] = tsong;
					answer[1][1] = tidx;
				}
				else {
					answer[1][0] = answer[0][0];
					answer[1][1] = answer[0][1];
					answer[0][0] = tsong;
					answer[0][1] = tidx;
				}
			}
			
			else if(answer[0][0] !=0 && answer[1][0] !=0) {
				if(tsong <answer[0][0])
					continue;
				else if(tsong>=answer[0][0] && tsong<answer[1][0]) {
					if(tsong == answer[0][0]){
						if(tidx > answer[0][1])
							continue;
					}
					answer[0][0] = tsong;
					answer[0][1] = tidx;
				}
				else if(tsong>= answer[1][0]) {
					if(tsong == answer[1][0]){
						if(tidx> answer[1][1]) {
							answer[1][0] = answer[1][0];
							answer[1][1] = answer[1][1];
							answer[0][0] = tsong;
							answer[0][1] = tidx;
						}
					}
					else {
						answer[0][0] = answer[1][0];
						answer[0][1] = answer[1][1];
						answer[1][0] = tsong;
						answer[1][1] = tidx;
					}
				}
			}
		}
		
		if(ck == false) {
			int realan[] = new int[1];
			realan[0] = answer[0][1];
			
			return realan;
		}
		
		else {
			int realan[] = new int[2];
			realan[0] = answer[1][1];
			realan[1] = answer[0][1];
			
			return realan;
		}
	}
	
    static public int[] solution(String[] genres, int[] plays) {
        HashMap<String, Integer> sum = new HashMap<>();
        
        String ya[] = new String[genres.length];
        
        for(int i=0; i<genres.length; i++) {
        	ya[i] = genres[i] + "," + plays[i] + "," + i;
        	if(sum.containsKey(genres[i]))
        		sum.put(genres[i], sum.get(genres[i]) + plays[i]);
        	else
        		sum.put(genres[i], plays[i]);
        }
        
        LinkedList<String> sorted = new LinkedList<>();
        for(String key: sum.keySet())
        	sorted.add(sum.get(key) + "," + key);
        
        Collections.sort(sorted, Collections.reverseOrder());
        
        LinkedList<Integer> answer = new LinkedList<>();
        
        for(int i=0; i<sorted.size(); i++) {
        	String real[] = sorted.get(i).split(",");
        	LinkedList<Pos> tm = new LinkedList<Pos>();
        	
        	for(int j=0; j<genres.length; j++) {
        		String split[] = ya[j].split(",");
        		if(ya[j].contains(real[1])) {
        			tm.add(new Pos(Integer.parseInt(split[1]), Integer.parseInt(split[2])));
        		}
        	}
        	
        	int two[] = calculation(tm);
        	
        	for(int k=0; k<two.length; k++)
        		answer.add(two[k]);
        }
        
        return answer.stream().mapToInt(i->i).toArray();
    }
	
	public static void main(String[] args) {
		String g[] = {"classic", "pop","pop", "pop", "classic", "classic", "hip"};
		int p[] = {500,500, 600, 600, 150, 800, 50000};
		
		int sol[] = solution(g,p);
		
		for(int i=0; i<sol.length; i++)
			System.out.println(sol[i]);
	}
}

후기 (2h) -> fail…

두시간을 풀었는데도… 예제도 다 맞는데… 어떤 테케에서 걸려서 60점밖에 못맞는지는 모르겠지만…

역대급으로 복잡한 단순 구현 문제…아아ㅏ아ㅏㅏ

Read More

[프로그래머스] 짝지어 제거하기 (java) Stack

2020-04-06

짝지어 제거하기 (프로그래머스> Stack_Queue)

문제 링크

문제설명

짝지어 제거하기는, 알파벳 소문자로 이루어진 문자열을 가지고 시작합니다. 먼저 문자열에서 같은 알파벳이 2개 붙어 있는 짝을 찾습니다. 그다음, 그 둘을 제거한 뒤, 앞뒤로 문자열을 이어 붙입니다. 이 과정을 반복해서 문자열을 모두 제거한다면 짝지어 제거하기가 종료됩니다. 문자열 S가 주어졌을 때, 짝지어 제거하기를 성공적으로 수행할 수 있는지 반환하는 함수를 완성해 주세요. 성공적으로 수행할 수 있으면 1을, 아닐 경우 0을 리턴해주면 됩니다.

예를 들어, 문자열 S = baabaa 라면

b aa baa → bb aa → aa

의 순서로 문자열을 모두 제거할 수 있으므로 1을 반환합니다.

제한사항
  • 문자열의 길이 : 1,000,000이하의 자연수
  • 문자열은 모두 소문자로 이루어져 있습니다.

입출력 예
s result
baabaa 1
cdcd 0
입출력 예 설명

입출력 예 #1 위의 예시와 같습니다. 입출력 예 #2 문자열이 남아있지만 짝지어 제거할 수 있는 문자열이 더 이상 존재하지 않기 때문에 0을 반환합니다.


풀이

package Stack_Queue;

import java.util.*;

//10min
public class prog_2_짝지어제거하기 {

    public int solution(String s){
        Stack<Character> stk = new Stack<>();
        
        for(int i=s.length()-1; i>=0; i--) {
        	char now = s.charAt(i);
        	if(!stk.isEmpty() && stk.peek() == now)
        		stk.pop();
        	else
        		stk.add(now);
        }
        
        if(stk.isEmpty())
        	return 1;
        else
        	return 0;
        
    }
}

후기 (10min)

며칠 전 풀었던 **<문자열 폭발="">**이라는 문제와 거의 유사했다!

뒤에서 부터 넣으면서 같으면 pop 없으면 push하는 방법으로 짝지어서 제거할 수 있었다!

Read More

[프로그래머스] 조이스틱 (java) Greedy

2020-04-06

조이스틱 (프로그래머스> Greedy)

문제 링크

문제설명

조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다. ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA

조이스틱을 각 방향으로 움직이면 아래와 같습니다.

▲ - 다음 알파벳
▼ - 이전 알파벳 (A에서 아래쪽으로 이동하면 Z로)
◀ - 커서를 왼쪽으로 이동 (첫 번째 위치에서 왼쪽으로 이동하면 마지막 문자에 커서)
▶ - 커서를 오른쪽으로 이동

예를 들어 아래의 방법으로 JAZ를 만들 수 있습니다.

- 첫 번째 위치에서 조이스틱을 위로 9번 조작하여 J를 완성합니다.
- 조이스틱을 왼쪽으로 1번 조작하여 커서를 마지막 문자 위치로 이동시킵니다.
- 마지막 위치에서 조이스틱을 아래로 1번 조작하여 Z를 완성합니다.
따라서 11번 이동시켜 "JAZ"를 만들 수 있고, 이때가 최소 이동입니다.

만들고자 하는 이름 name이 매개변수로 주어질 때, 이름에 대해 조이스틱 조작 횟수의 최솟값을 return 하도록 solution 함수를 만드세요.

제한 사항
  • name은 알파벳 대문자로만 이루어져 있습니다.
  • name의 길이는 1 이상 20 이하입니다.
입출력 예
name return
JEROEN 56
JAN 23


풀이

package Greedy;

import java.util.*;

public class prog_2_조이스틱 {
	
    static public int solution(String name) {
        int answer = 0;
        
        int len = name.length();
        
        //최대로 가질 수 있는 min값은 끝까지 가는것
        int min_move = len-1;
        
        for(int i=0; i<len; i++) {
        	answer += Math.min(name.charAt(i)-'A', 'Z'-name.charAt(i)+1);
        	
        	//좌우: 연속된 A의 등장에 따라 최소 움직임이 달라진다
        	int next = i+1;// 현재 다음 위치부터
        	//내 다음이 A라면 계속 NEXT++
        	while(next<len && name.charAt(next) == 'A')
        		next++;
        	
        	min_move = Math.min(min_move, i+len-next + i);
        }//for
        
        answer += min_move;
        
        return answer;
    }
	
    
	public static void main(String[] args) {
		System.out.println(solution("AABA"));
	}
}
 

후기 (30min)

거의 두세달 전에 도전했다가 이해 못해서 나가 떨어졌던 문제…!

였으나 이제 어느정도 이해된 문제!

  1. 조이스틱을 움직여서 가질 수 있는 가장 큰 이동 값은, 차례로 움직여 len까지 가는 것이다.
  2. 그 값을 min이라고 초기화 해두고 int min_move = len-1;
  3. 이 문제의 키포인트는 연속된 A의 등장에 따라 최소 움직임이 달라진다는 것이다!
  4. 따라서 min_move와 비교해주어야 하는 값은,
  5. 내 위치에서 첫위치로 돌아간 후 (i+i)
  6. A가 연속으로 나오는 지점의 다음 (next)을 끝(len)에서 계산해 주는 것이다 -> len-next
  7. 따라서 min(min_move, i+i+ (len-next));


다른 블로그에서 참고한 부분!

// len - next : 
// 총 길이에서 현재 바로 다음에 연속된 A가 지나고 남은 문자 갯수
// i : 오른쪽으로의 현재까지의 이동횟수
// i + len - next + i : 현재까지 왔다가 다시 돌아가서 남은 거 까지 가는 이동 횟수
// min(i,len-next)에서,
// i 보다 len-next 값이 작은 경우에 len-next를 선택하는데
// 이는, 마지막 문자가 A인 경우를 제외 하면
// 무조건 len-1 보다 크게 된다 (len-next >=1)
// 따라서,i가 len-next(남은 문자)보다 큰 경우는
// 굳이 왼쪽으로 다시 돌아갈 필요가 없다.
// 대신 끝이 A인 경우는, len-next가 0이 되므로,
// 무조건 len-1 보다 작은 i 가 최소 이동횟수가 된다.
// 따라서 Math.min(i,len-next) 이 부분은 식에서 필요하게 된다.
	min_move = Math.min(min_move, Math.min(i+len-next+ Math.min(i,len-next) ));
Read More

[Coding test] 0405_no.5 (java)

2020-04-05

Coding test / 0405_no.5

문제설명

유출 x

풀이

package T0405;

import java.util.*;


//25 min
public class t5 {
    public static String[] solution(String[][] dataSource, String[] tags) {
 
        int size[][] = new int[dataSource.length][2];
        
        for(int i=0; i<size.length; i++)
        	size[i][1] = i;
        
        String tg = "";
        for(int i=0;i<tags.length; i++)
        	tg += tags[i];
        
        for(int i=0;i<dataSource.length; i++) {
        	for(int j=1; j<dataSource[i].length; j++) {
        		if(tg.contains(dataSource[i][j]))
        			size[i][0]++;
        	}
        }

        Arrays.sort(size, new Comparator<int[]>() {
        	@Override
        	public int compare(int a[], int b[]) {
        		if(a[0] == b[0])
        			return a[1] - b[1];
        		else
        			return b[0]-a[0];
        	}
        });

        String ans = "";

        for(int i=0; i<size.length; i++) {
        	if(size[i][0] != 0) {
        		int idx = size[i][1];
        		
        		ans += dataSource[idx][0] + ",";
        	}
        }
        
        String[] answer = ans.split(",");
        String[] realan = new String[10];
        
        if(answer.length >10) {
        	for(int i=0 ;i<10; i++)
        		realan[i] = answer[i];
        	
        	return realan;
        }
        
        return answer;
    }
    
    public static void main(String[] args) {
		String s[][] = doc1,
				{"doc2", "t0", "t2", "t3"},
			    {"doc3", "t1", "t6", "t7"},
			    {"doc4", "t1", "t2", "t4"},
			    {"doc5", "t6", "t100", "t8"}};
		
		String t[] = {"t1", "t2", "t3"};
		
		solution(s,t);

	}
}

후기 (25min)

이것 또한 테케는 나왔으나 정답인지는 모르겠는 문제 중 하나…

일단 10개 이상이면 10만 출력하라는 조건은 만족시켰고

그 외에 doc1 부터 doc…까지 태그를 가지고 있는지 비교해줬다.

이 부분이 약간 야매인게, tag 의 t1t2t3을 string에 넣어버리고 doc이 tag를 포함하면 +1을 시켜주는 방식으로….ㅎ 진행했다

그리고 tag를 많이 가진 순으로 compare해줬고 tag 개수가 같다면 doc 이름의 오름차순으로 정렬해줬다

또한, 문자열의 배열로 return 해야했기때문에 전부 ,(컴마)를 넣어주고 split 해서 return 했으며

split한 문서가 10개 이하면 바로 return 아닌 경우에는 10개만 넣어서 따로 return 해주었다

Read More

[Coding test] 0405_no.4 (java)

2020-04-05

Coding test / 0405_no.4

문제설명

유출 x

풀이

package T0405;

import java.util.*;

//50min
public class t4 {
    public static String[][] solution(String[][] snapshots, String[][] transactions) {
        TreeMap<String, String> tran = new TreeMap<>();
        TreeMap<String, Integer> snap = new TreeMap<>();
        
        
        for(int i=0; i<snapshots.length; i++)
        	snap.put(snapshots[i][0], Integer.parseInt(snapshots[i][1]));
        
        
        for(int i=0; i<transactions.length; i++) {
        	if(tran.containsKey(transactions[i][0]))
        		continue;
        	else {
        		String s = "";
        		for(int j=1; j<transactions[i].length; j++)
        			s += transactions[i][j] + ",";
        		tran.put(transactions[i][0], s);
        	}
        }
        
       for(String key:tran.keySet()) {
    	   String re[] = tran.get(key).split(",");
    	   
    	   if(re[0].equals("SAVE")) {
    		   if(snap.containsKey(re[1]))
    			   snap.put(re[1], Integer.parseInt(re[2]) + snap.get(re[1]));
    		   else
    			   snap.put(re[1], Integer.parseInt(re[2]));
    	   }
    	   
    	   if(re[0].equals("WITHDRAW")) {
    		   if(snap.containsKey(re[1]))
    			   snap.put(re[1], snap.get(re[1]) - Integer.parseInt(re[2]));
    	   }
    	   
       }
       
       String real = "";
       for(String key:snap.keySet()) {
    	   System.out.println(key + " " + snap.get(key));
    	   real += key + "," + snap.get(key)+",";
       }
       
       String[][] answer = new String[snap.size()][2];
       String rs[] = real.split(",");
       
       int idx = 0;
       for(int i=0; i<answer.length; i++) {
    	   answer[i][0] = rs[idx++];
    	   answer[i][1] = rs[idx++];
       }
       
       return answer;
    }
	
	public static void main(String[] args) {
		String t[][] = {
				{"ACCOUNT1", "100"}, 
		                {"ACCOUNT2", "150"}
		};
		String s[][] = {
		                {"1", "SAVE", "ACCOUNT2", "100"},
		                {"2", "WITHDRAW", "ACCOUNT1", "50"}, 
		                {"1", "SAVE", "ACCOUNT2", "100"}, 
		                {"4", "SAVE", "ACCOUNT3", "500"}, 
		                {"3", "WITHDRAW", "ACCOUNT2", "30"}
		                };
		
		System.out.println(solution(t,s));
	}
}

후기 (50min)

쓸데 없는 곳에서 시간을 너무 많이 쏟았다…

save할 때, 새로 들어온 값이면 put(re[1], Integer.parseInt(re[2])) 해야하는데 엉뚱한 값을 넣어놔서 계속 null 로 뜬 것도 그렇고

키 값을 오름차순으로 정렬하기 위해서 HashMap(값의 정렬 X)을 쓰고 어버버 하다가 사전 순으로 정렬해준다는 TreeMap(키 값으로 정렬 O)을 사용해 쉽게 풀 수 있었다.

key value 가져오는 법, 매번 검색하지말고 이참에 좀 익혀두자!

    TreeMap<String, Integer> snap = new TreeMap<>();    

	for(String key:snap.keySet())
    	   System.out.println(key + " " + snap.get(key));
Read More