문제

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 


코드

import java.util.HashMap;
import java.util.Map;

public class Solution {
	String[] answer;
	Map<String, Integer> indexMap;

	public String[] solution(String[] players, String[] callings) {
		answer = players;
		indexMap = new HashMap<>();

		for (int i = 0; i < players.length; i++) {
			indexMap.put(players[i], i);
		}
		for (String call : callings) {
			swap(findIndex(call));
		}
		return answer;
	}

	// 인덱스 찾기
	private int findIndex(String call) {
		return indexMap.get(call);
	}

	void swap(int i) {
		// 인덱스 갱신
		indexMap.put(answer[i - 1], i);
		indexMap.put(answer[i], i - 1);
		// 스왑
		String tmp = answer[i - 1];
		answer[i - 1] = answer[i];
		answer[i] = tmp;
	}
}

HashMap이 핵심이다. 

해시를 이용해 자료 접근에 필요한 시간 복잡도를 상수 1 로 만든다.

 

추가로 swap()에서 반드시 indexMap을 갱신해줘야 한다.

 

'자료구조&알고리즘' 카테고리의 다른 글

버블 정렬, 선택 정렬, 삽입 정렬  (0) 2023.07.02

https://www.udemy.com/course/best-javascript-data-structures/

 

테스트 값

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

public class SortEx01 {
	public static void main(String[] args) {
		ThreadLocalRandom current = ThreadLocalRandom.current();
		Integer[] array = current.ints(0,300).distinct().limit(10).boxed().toArray(Integer[]::new);
		System.out.println(array.getClass().getSimpleName()+"   "+ Arrays.toString(array));
		
		//정렬들 저장용
		List<SortStategy<Integer>> list = new ArrayList<>();
		
		for(SortStategy<Integer> sort : list) 
			System.out.printf("%-20s  %s%n",sort.getClass().getSimpleName(),
					Arrays.toString(sort.sort(array)));
	}
	
	static interface SortStategy<T>{
		T[] sort(T[] arr);
		//자리 바꿈 메서드
		default void swap(Integer[] clone, int i, int j) {
			Integer tmp = clone[i];
			clone[i] = clone[j];
			clone[j] = tmp;
		}
	}
}

 

버블 정렬

큰 값을 뒤로 보내며, 최대반복 수를 점점 줄여간다.

static class BubbleSort implements SortStategy<Integer>{
    static int cnt = 0;

    public Integer[] sort(Integer[] arr) {
        Integer[] clone = arr.clone();

        for(int i=0;i<clone.length-1;i++) {// n -1 번 수행
            for(int j=1;j<clone.length-i;j++) {
                cnt++;
                if(clone[j]<clone[j-1]) {
                    swap(clone, j-1, j);
                }
            }
            System.out.println(Arrays.toString(clone));
        }
        System.out.print("버블소트 cnt("+cnt+")");
        return clone;
    }
}
Integer[]   [113, 247, 171, 173, 243, 35, 66, 223, 85, 83]
[113, 171, 173, 243, 35, 66, 223, 85, 83, 247]
[113, 171, 173, 35, 66, 223, 85, 83, 243, 247]
[113, 171, 35, 66, 173, 85, 83, 223, 243, 247]
[113, 35, 66, 171, 85, 83, 173, 223, 243, 247]
[35, 66, 113, 85, 83, 171, 173, 223, 243, 247]
[35, 66, 85, 83, 113, 171, 173, 223, 243, 247]
[35, 66, 83, 85, 113, 171, 173, 223, 243, 247]
[35, 66, 83, 85, 113, 171, 173, 223, 243, 247]
[35, 66, 83, 85, 113, 171, 173, 223, 243, 247]
버블소트 cnt(45)BubbleSort            [35, 66, 83, 85, 113, 171, 173, 223, 243, 247]

최대 값이 제일 뒤로 가니, 그에 따라 최대 반복 수를 줄여 정렬한다.

 

버블 정렬 최적화

static class BubbleSortOp implements SortStategy<Integer>{
    Boolean noSwap = false;
    static int cnt = 0;

    public Integer[] sort(Integer[] arr) {
        Integer[] clone = arr.clone();

        for(int i=0;i<clone.length-1;i++) {// n -1 번 수행용 반복문
            noSwap = true;
            for(int j=1;j<clone.length-i;j++) {//자리바꿈 루프
                cnt++;
                if(clone[j]<clone[j-1]) {
                    noSwap = false; // 자리바꿈이 한 번이라도 수행됐다.
                    swap(clone, j-1, j);
                }
            }
            if(noSwap) break; //자리 바꿈이 수행된적이 없으면 수행용 반복은 의미없음
        }
        System.out.print("버블소트 최적화 cnt("+cnt+")");
        return clone;
    }
}

더 이상 교환된 값이 없으면, 더 이상 정렬한 값이 없는 것으로 반복문을 빠져나온다.

Integer[]   [286, 172, 22, 197, 169, 62, 236, 99, 141, 156]
버블소트 cnt(45)BubbleSort            [22, 62, 99, 141, 156, 169, 172, 197, 236, 286]
버블소트 최적화 cnt(39)BubbleSortOp          [22, 62, 99, 141, 156, 169, 172, 197, 236, 286]

선택 정렬

지정된 위치에 최적에 값을 넣는다. 

가장 안 좋은 정렬이다. 어떠한 경우에도 n^2 시간 복잡도를 보인다.

//버블 정렬보다 나은 점은 스왑수 최소화, i루프 마다 단 한번의 스왑만 발생
static class SelectionSort implements SortStategy<Integer>{
    public Integer[] sort(Integer[] arr) {
        Integer[] clone = arr.clone();
        for(int i=0;i<clone.length-1;i++) {
            for(int j=i+1;j<clone.length;j++) {
                if(Integer.compare(clone[i], clone[j])>0) {
                    swap(clone, i, j);
                }
            }
        }
        return clone;
    }
}

삽입 정렬

논리적으로 배열안에 서브 배열을 만들어 점차 정렬해가는 정렬

배열의 요소가 1개면, 자연스럽게 정렬된 상태다. 즉, 배열의 요소가 2개부터 정렬이 가능한 상태로 시작 인덱스는 1로 준다.

배열의 요소가 거의 정렬된 상태일 때 매우 빠른 속도를 보인다.

static class InsertSort implements SortStategy<Integer>{
    //논리적으로 순회 마다 작은 서브배열을 만든다고 가정한다.
    //1부터 시작
    public Integer[] sort(Integer[] arr) {
        Integer[] clone = arr.clone();
        //배열이 단 한개는 이미 정렬된 것이다. (논리적 배열)
        for(int i = 1;i<clone.length;i++) {
            //배열 shift 하는 동안 값 손실 때문이 임시 저장
            Integer newMember = clone[i];
            Integer j = i-1;
            //새로운 멤버 clone[i]
            for(;j>=0 && newMember < clone[j];j--) {
                clone[j+1] = clone[j];
            }
            //들어갈 자리 j-- 보정 값 +1
            clone[j+1] = newMember;
        }
        return clone;
    }
}

전체 코드

package udemyjavascript;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

public class SortEx01 {
	public static void main(String[] args) {
		ThreadLocalRandom current = ThreadLocalRandom.current();
		Integer[] array = current.ints(0,300).distinct().limit(10).boxed().toArray(Integer[]::new);
		System.out.println(array.getClass().getSimpleName()+"   "+ Arrays.toString(array));
		
		//정렬들 저장용
		List<SortStategy<Integer>> list = new ArrayList<>();
		list.add(new BubbleSort());
		list.add(new BubbleSortOp());
		list.add(new SelectionSort());
//		list.add(new InsertSort());
		
		for(SortStategy<Integer> sort : list) 
			System.out.printf("%-20s  %s%n",sort.getClass().getSimpleName(),
					Arrays.toString(sort.sort(array)));
	}
	
	static interface SortStategy<T>{
		T[] sort(T[] arr);
		//자리 바꿈 메서드
		default void swap(Integer[] clone, int i, int j) {
			Integer tmp = clone[i];
			clone[i] = clone[j];
			clone[j] = tmp;
		}
	}
	
	static class BubbleSort implements SortStategy<Integer>{
		static int cnt = 0;
		
		public Integer[] sort(Integer[] arr) {
			Integer[] clone = arr.clone();
			
			for(int i=0;i<clone.length-1;i++) {// n -1 번 수행
				for(int j=1;j<clone.length-i;j++) {
					cnt++;
					if(clone[j]<clone[j-1]) {
						swap(clone, j-1, j);
					}
				}
			}
			System.out.print("버블소트 cnt("+cnt+")");
			return clone;
		}
	}
	static class BubbleSortOp implements SortStategy<Integer>{
		Boolean noSwap = false;
		static int cnt = 0;
		
		public Integer[] sort(Integer[] arr) {
			Integer[] clone = arr.clone();
			
			for(int i=0;i<clone.length-1;i++) {// n -1 번 수행용 반복문
				noSwap = true;
				for(int j=1;j<clone.length-i;j++) {//자리바꿈 루프
					cnt++;
					if(clone[j]<clone[j-1]) {
						noSwap = false; // 자리바꿈이 한 번이라도 수행됐다.
						swap(clone, j-1, j);
					}
				}
				if(noSwap) break; //자리 바꿈이 수행된적이 없으면 수행용 반복은 의미없음
			}
			System.out.print("버블소트 최적화 cnt("+cnt+")");
			return clone;
		}
	}
	
	//버블 정렬보다 나은 점은 스왑수 최소화, i루프 마다 단 한번의 스왑만 발생
	static class SelectionSort implements SortStategy<Integer>{
		public Integer[] sort(Integer[] arr) {
			Integer[] clone = arr.clone();
			for(int i=0;i<clone.length-1;i++) {
				for(int j=i+1;j<clone.length;j++) {
					if(Integer.compare(clone[i], clone[j])>0) {
						swap(clone, i, j);
					}
				}
			}
			return clone;
		}
	}
	
	static class InsertSort implements SortStategy<Integer>{
		//논리적으로 순회 마다 작은 서브배열을 만든다고 가정한다.
		//1부터 시작
		public Integer[] sort(Integer[] arr) {
			Integer[] clone = arr.clone();
			//배열이 단 한개는 이미 정렬된 것이다. (논리적 배열)
			for(int i = 1;i<clone.length;i++) {
				//배열 shift 하는 동안 값 손실 때문이 임시 저장
				Integer newMember = clone[i];
				Integer j = i-1;
				//새로운 멤버 clone[i]
				for(;j>=0 && newMember < clone[j];j--) {
					clone[j+1] = clone[j];
				}
				//들어갈 자리 j-- 보정 값 +1
				clone[j+1] = newMember;
			}
			return clone;
		}
	}
}
Integer[]   [297, 76, 286, 161, 206, 20, 61, 160, 3, 9]
버블소트 cnt(45)BubbleSort            [3, 9, 20, 61, 76, 160, 161, 206, 286, 297]
버블소트 최적화 cnt(45)BubbleSortOp          [3, 9, 20, 61, 76, 160, 161, 206, 286, 297]
SelectionSort         [3, 9, 20, 61, 76, 160, 161, 206, 286, 297]

 

정렬 속도 비교

https://www.toptal.com/developers/sorting-algorithms

 

Sorting Algorithms Animations

Animation, code, analysis, and discussion of 8 sorting algorithms on 4 initial conditions.

www.toptal.com

 

'자료구조&알고리즘' 카테고리의 다른 글

달리기 경주  (0) 2023.07.14

코드

import java.util.ArrayList;
import java.util.Collections;

/**
 * 벽돌은 가장 넓은 것이 아래에 위치
 * 그리고 가장 무거운 것일 수록 아래 위치
 */
public class 가장높은탑쌓기{

	static class Brick implements Comparable<Brick>{
		public final int width, heigth, weight;
		public Brick(int width, int heigth, int weight) {
			this.width = width;
			this.heigth = heigth;
			this.weight = weight;
		}
		public int compareTo(Brick o){
			return o.width-this.width;
		}
	}
	
	static int[] dy;
	static ArrayList<ArrayList<Brick>> list;
	
	public static void main(String[] args){
		int[][] input = 
			{
					{25, 3, 4 }
					,{4 ,4 ,6  }
					,{9 ,2 ,3  }
					,{16, 2, 5 }
					,{1 ,5 ,2  }
			};
		int n=input.length;
		
		ArrayList<Brick> arr=new ArrayList<>();
		
		dy=new int[n];
		for(int i=0; i<n; i++){
			int a= input[i][0] ;
			int b= input[i][1] ;
			int c= input[i][2] ;
			arr.add(new Brick(a, b, c));
		}
		System.out.print(solution(arr));
	}
	
	static int solution(ArrayList<Brick> arr){
		//너비 순으로 내림차순
		Collections.sort(arr);
		dy[0]=arr.get(0).heigth;
		int answer= dy[0];
		
		//높이 비교 1부터
		for(int i=1; i<arr.size(); i++){
			//높이 tmp
			int max_h=0;
			//이전 벽돌 비교
			for(int j=i-1; j>=0; j--){
				//무게는 j가 커야한다. 그리고 그 중에 제일 높은 값을 구한다.
				if(arr.get(j).weight > arr.get(i).weight && dy[j]>max_h){
					max_h=dy[j];
				}
			}
			//제일 높은 값을 구했으니, 그 값에 나의 높이를 더 한다.
			dy[i]=max_h+arr.get(i).heigth;
			//지금까지 높이 중 가장 큰 높이를 구한다.
			answer=Math.max(answer, dy[i]);
		}
		return answer;
	}
}

결과

10

이전 최대부분증가수열과 거의 같다. 

일부 특수화가 됐을 뿐이다.

 

'자료구조&알고리즘 > 자바(Java) 알고리즘 문제풀이 : 코딩테스트 대비' 카테고리의 다른 글

최대부분증가 수열  (0) 2023.04.27
돌다리 건너기  (0) 2023.04.25
계단오르기  (0) 2023.04.24
다익스트라 알고리즘  (0) 2023.04.22
씨름선수  (0) 2023.04.07

코드

import java.util.Arrays;

public class 최대부분증가수열연습 {
	static int dy[];
	
 	public static void main(String[] args) {
 		//수열
		int[] arr = {5, 3, 7, 8, 6, 2, 9, 4};
		System.out.println(solution(arr));
	}
	static int solution(int[] arr) {
		int answer = 0;
		dy = new int[arr.length];
		dy[0] = 1;
		//수열 순회
		for(int i=1;i<arr.length;i++) {
			//수열 수 저장
			int max = 0;
			//현재 수열 이전 값 중 작은 값있는지 탐색
			for(int j=i;j>=0;j--) {
				//현재 수열보다 작은 값 있으면, 거기에 저장된 수열 횟수 저장
				if(arr[i]>arr[j]) {
					max = Math.max(max, dy[j]);
				}
			}
			//구해진 수열 수에 +1
			dy[i] = max+1;
			//최종적으로 가장 횟수 많은 부분 수열을 구함
			answer = Math.max(answer, dy[i]);
		}
		System.out.println(Arrays.toString(arr));
		System.out.println(Arrays.toString(dy));
		return answer;
	}
}

결과

[5, 3, 7, 8, 6, 2, 9, 4]
[1, 1, 2, 3, 2, 1, 4, 2]
4

9가 있는 위치를 기준으로 설명

이 기준으로 탐색을 시작

그 값에 +1을 한 것

 

왜 3을 찾아서 +1을 했는가?

8을 기준으로 하면 최대 부분 증가 수열은 3이다.

5-7-8 or -3-7-8  3개

 

9 값이전에서 가장 큰 최대 부분 증가 수열 수는 3이다.

그 값에 +1을 한 것

 

바텀업 방식으로 값을 구한 것이다.

 

문제의 본질을 유지한 상태로 작은 케이스부터 큰 케이스를 탐색하는 방식

 

 

'자료구조&알고리즘 > 자바(Java) 알고리즘 문제풀이 : 코딩테스트 대비' 카테고리의 다른 글

가장높은탑쌓기  (0) 2023.04.30
돌다리 건너기  (0) 2023.04.25
계단오르기  (0) 2023.04.24
다익스트라 알고리즘  (0) 2023.04.22
씨름선수  (0) 2023.04.07

코드


public class 돌다리건너기 {
	static int[] dy;
	static int[] memo;
	
	static int cnt = 0;
	
	public static void main(String[] args) {
		int goal = 10; // 돌다리 개수
		goal +=1; //1개를 더한다
		
		dy = new int[goal+1];
		memo = new int[goal+1];
		
		long start = System.nanoTime();
		System.out.println("answer = " +dy(goal));
		System.out.println(cnt);
		System.out.println(System.nanoTime()-start);
		
		start = System.nanoTime();
		cnt=0;
		System.out.println("answer = "+noDy(goal));
		System.out.println(cnt);
		System.out.println(System.nanoTime()-start);
		
		start = System.nanoTime();
		cnt=0;
		System.out.println("answer = "+noDyMemo(goal));
		System.out.println(cnt);
		System.out.println(System.nanoTime()-start);
		
	}

	private static int dy(int goal) {
		dy[1] = 1;
		dy[2] = 2;
		for(int i=3;i<=goal;i++,cnt++) {
			dy[i] = dy[i-1]+dy[i-2];
		}
		return dy[goal];
	}
	
	static int noDy(int goal) {
		cnt++;
		if(goal==1) return 1;
		else if (goal==2) return 2;
		else return noDy(goal-1)+noDy(goal-2);
	}
	
	static int noDyMemo(int goal) {
		cnt++;
		if(goal==1) return 1;
		else if (goal==2) return 2;
		else if(memo[goal]>0) return memo[goal];
		else return memo[goal]=noDyMemo(goal-1)+noDyMemo(goal-2);
	}
}

결과

answer = 144
9
765600
answer = 144
177
47600
answer = 144
19
21900

계단 같은 경우는 계단에 도착한게 도착지지만, 

돌다리의 경우 건너편을 건너기 위한 돌다리 개수를 받았기 때문에 최종 돌다리가 목적지가 아니라 +1 한 건너편이 목적지다

'자료구조&알고리즘 > 자바(Java) 알고리즘 문제풀이 : 코딩테스트 대비' 카테고리의 다른 글

가장높은탑쌓기  (0) 2023.04.30
최대부분증가 수열  (0) 2023.04.27
계단오르기  (0) 2023.04.24
다익스트라 알고리즘  (0) 2023.04.22
씨름선수  (0) 2023.04.07

코드

//계단을 오를 땐 한 번에 1개, 2개씩 오를 수 있다.

public class 계단오르기 {
	static int[] dy;
	static int[] memo;
	
	static int cnt = 0;
	
	public static void main(String[] args) {
		int goal = 10; //10계단까지 가는 방법
		dy = new int[goal+1];
		memo = new int[goal+1];
		
		System.out.println("answer = " +dy(goal));
		System.out.println(cnt);
		cnt=0;
		System.out.println("answer = "+noDy(goal));
		System.out.println(cnt);
		cnt=0;
		System.out.println("answer = "+noDyMemo(goal));
		System.out.println(cnt);
		
	}

	private static int dy(int goal) {
		dy[1] = 1;
		dy[2] = 2;
		for(int i=3;i<=goal;i++,cnt++) {
			dy[i] = dy[i-1]+dy[i-2];
		}
		return dy[goal];
	}
	
	static int noDy(int goal) {
		cnt++;
		if(goal==1) return 1;
		else if (goal==2) return 2;
		else return noDy(goal-1)+noDy(goal-2);
	}
	
	static int noDyMemo(int goal) {
		cnt++;
		if(goal==1) return 1;
		else if (goal==2) return 2;
		else if(memo[goal]>0) return memo[goal];
		else return memo[goal]=noDyMemo(goal-1)+noDyMemo(goal-2);
	}
}

결과

answer = 89
8
answer = 89
109
answer = 89
17

큰 문제의 본질을 그대로 유지한 상태로 작게 축소하여 계산해 이를 이용해 큰 문제를 해결하는 방법

 

동적 계획법으로 풀었을 때는 8번 반복(1,2는 수동으로 입력했음) 

 

그냥 큰 문제로 바로 풀었을 경우 109번의 반복(재귀)

 

큰 문제를 메모이제이션으로 풀었을 경우 17번의 반복(재귀)

 

 

public class 계단오르기 {
	static int[] dy;
	static int[] memo;
	
	static int cnt = 0;
	
	public static void main(String[] args) {
		int goal = 50;
		dy = new int[goal+1];
		memo = new int[goal+1];
		
		long start = System.nanoTime();
		System.out.println("answer = " +dy(goal));
		System.out.println(cnt);
		System.out.println(System.nanoTime()-start);
		
		start = System.nanoTime();
		cnt=0;
		System.out.println("answer = "+noDy(goal));
		System.out.println(cnt);
		System.out.println(System.nanoTime()-start);
		
		start = System.nanoTime();
		cnt=0;
		System.out.println("answer = "+noDyMemo(goal));
		System.out.println(cnt);
		System.out.println(System.nanoTime()-start);
		
	}

	private static int dy(int goal) {
		dy[1] = 1;
		dy[2] = 2;
		for(int i=3;i<=goal;i++,cnt++) {
			dy[i] = dy[i-1]+dy[i-2];
		}
		return dy[goal];
	}
	
	static int noDy(int goal) {
		cnt++;
		if(goal==1) return 1;
		else if (goal==2) return 2;
		else return noDy(goal-1)+noDy(goal-2);
	}
	
	static int noDyMemo(int goal) {
		cnt++;
		if(goal==1) return 1;
		else if (goal==2) return 2;
		else if(memo[goal]>0) return memo[goal];
		else return memo[goal]=noDyMemo(goal-1)+noDyMemo(goal-2);
	}
}
answer = -1109825406
48
648700
answer = -1109825406
-597265727
40278105300
answer = -1109825406
103
37300

50을 줬을때 반복횟수와 소요시간

'자료구조&알고리즘 > 자바(Java) 알고리즘 문제풀이 : 코딩테스트 대비' 카테고리의 다른 글

최대부분증가 수열  (0) 2023.04.27
돌다리 건너기  (0) 2023.04.25
다익스트라 알고리즘  (0) 2023.04.22
씨름선수  (0) 2023.04.07
피자배달거리DFS  (0) 2023.04.05

코드

import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.stream.Stream;

public class 다익스트라연습 {
	private static class Edge implements Comparable<Edge>{
	    private final int vex;
	    private final int cost;
		
		private Edge(int vex, int cost) {
	        this.vex = vex;
	        this.cost = cost;
	    }
	    public int compareTo(Edge ob){
	        return Integer.compare(this.cost,ob.cost);
	    }
	    public String toString() {
	    	return "["+vex+", "+cost+"]";
	    }
	}
	static ArrayList<ArrayList<Edge>> graph;
	static int[] dis;
	
	static void sol(int v) {
		//내부적으로 이분검색을 사용해 시간 복잡도가 log n
		PriorityQueue<Edge> q = new PriorityQueue<>();
		//시작 정점은 거리 0
		dis[v] = 0;
		//시작 정점은 비용 0
		q.offer(new Edge(v, 0));
		while(!q.isEmpty()) {
			//자료구조 상 가장 비용이 작은 정점이 나온다.
			Edge cur = q.poll();
			//현재 가장 작은 비용이 이미 저장된 비용보다 크면 확인할 필요가 없다.
			if(cur.cost>dis[cur.vex]) continue;
			//graph.get(cur.vex)은 n번 수행된다.
			//graph.get(cur.vex) 결과로 나온 Edge는 최소 n번 이상 수행된다.
			for(Edge next : graph.get(cur.vex)) {
				//다음 경로 비용 계산 시작
				//다음 경로에 이미 저장된 비용 > 현재까지 누산된 비용 + 다음 경로까지 비용
				if(dis[next.vex] > cur.cost + next.cost ) {
					dis[next.vex] = cur.cost + next.cost;
					//중요_ 현재까지 누산된 비용을 다음 경로까지 물고간다.
					q.offer(new Edge(next.vex, cur.cost + next.cost));
				}
			}
		}
	}
	
	public static void main(String[] args){
		//{간선시작, 간선끝, 가중치}
		int[][] arr = 
			{{1, 2, 12}
			,{1, 3, 4 }
			,{2, 1, 2 }
			,{2, 3, 5 }
			,{2, 5, 5 }
			,{3, 4, 5 }
			,{4, 2, 2 }
			,{4, 5, 5 }
			,{6, 4, 5 }	};
		
		graph = new ArrayList<ArrayList<Edge>>();
		graph.add(new ArrayList<>()); // 0 번 미사용
		System.out.println("==정점 만큼 골라내기==");
		Arrays.stream(arr)
			.flatMap(data -> Stream.of(data[0],data[1]))
			.distinct()
			.peek(data -> System.out.print(data+", "))
			.forEach( data -> graph.add(new ArrayList<>()));
		//거리비용 저장 배열
		dis = new int[graph.size()];
		Arrays.fill(dis, Integer.MAX_VALUE);
		
		System.out.println("\n==간선 정보==");
		Arrays.stream(arr)
			.peek(data->System.out.println(data[0]+"->" +data[1]+" 가중치:"+data[2]))
			.forEach(data ->graph.get(data[0]).add(new Edge(data[1], data[2])));
		
		sol(1);
		System.out.println("== 정점 별 최소 비용 ==");
		for(int i=2; i<graph.size(); i++){
			if(dis[i]!=Integer.MAX_VALUE) System.out.println(i+" : "+dis[i]);
			else System.out.println(i+" : impossible");
		}
	}
}

결과

==정점 만큼 골라내기==
1, 2, 3, 5, 4, 6, 
==간선 정보==
1->2 가중치:12
1->3 가중치:4
2->1 가중치:2
2->3 가중치:5
2->5 가중치:5
3->4 가중치:5
4->2 가중치:2
4->5 가중치:5
6->4 가중치:5
== 정점 별 최소 비용 ==
2 : 11
3 : 4
4 : 9
5 : 14
6 : impossible

우선순위 큐를 사용해 시간 복잡도를 줄인 것이 핵심

'자료구조&알고리즘 > 자바(Java) 알고리즘 문제풀이 : 코딩테스트 대비' 카테고리의 다른 글

돌다리 건너기  (0) 2023.04.25
계단오르기  (0) 2023.04.24
씨름선수  (0) 2023.04.07
피자배달거리DFS  (0) 2023.04.05
섬나라아일랜드BFS  (0) 2023.04.03

문제

https://school.programmers.co.kr/learn/courses/30/lessons/131705

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 


코드

class Solution {
	static int [] chkArr = new int[3];//삼총사
	static int [] intArr;
	static int answer = 0;
	
    public int solution(int[] number) {
        intArr = number;
        DFS(0,0);
        return answer;
    }
    
    void DFS(int lv, int s) {
		if(lv == 3) {
			int sum = 0;
			for(int x : chkArr) sum+=intArr[x];
			if(sum == 0) answer++;
		}else {
			for(int i =s; i< intArr.length;i++ ) {
				chkArr[lv] = i;
				DFS(lv+1, i+1);
			}
		}
    }
    
}

결과

테스트 1
입력값 〉	[-2, 3, 0, 2, -5]
기댓값 〉	2
실행 결과 〉	테스트를 통과하였습니다.
테스트 2
입력값 〉	[-3, -2, -1, 0, 1, 2, 3]
기댓값 〉	5
실행 결과 〉	테스트를 통과하였습니다.
테스트 3
입력값 〉	[-1, 1, -1, 1]
기댓값 〉	0
실행 결과 〉	테스트를 통과하였습니다.

경우의 수를 묻는 문제

경우의 수 마다 살짝 알고리즘을 더해 0이 되는지만 체크하면 된다.

'자료구조&알고리즘 > Level1' 카테고리의 다른 글

폰켓몬  (1) 2022.10.15
완주하지 못한 선수  (1) 2022.10.12
숫자 문자열과 영단어  (0) 2022.10.01
성격 유형 검사하기  (0) 2022.09.26
신고 결과 받기  (0) 2022.09.24

코드


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Main T = new Main();
		Scanner sc = new Scanner(System.in);
		ArrayList<Person> list = new ArrayList<Main.Person>();
		int size = sc.nextInt();
		for (int i = 0; i < size; i++) {
			list.add( T.new Person( sc.nextInt(), sc.nextInt() ) );
		}
		Collections.sort(list,Comparator.reverseOrder());
		
		System.out.println(T.solution(list));
		
		sc.close();
	}
	
	private int solution(ArrayList<Person> list) {
		int max = Integer.MIN_VALUE;
		int cnt = 0;
		
		for (Person person : list) {
			if(max<person.weight) {
				cnt++;
				max = person.weight;
			}
		}
		return cnt;
	}

	class Person implements Comparable<Person>{
		int height;
		int weight;
		public Person(int height, int weight) {
			super();
			this.height = height;
			this.weight = weight;
		}
		@Override
		public int compareTo(Person o) {
			return Integer.compare(this.height, o.height);
		}
		@Override
		public String toString() {
			return height+" "+weight;
		}
	}
	
}

입력

5
172 67
183 65
180 70
170 72
181 60

결과

3

넓은 의미의 그리디 알고리즘, 당장 최선의 선택을 함

키로 정렬해두면, 몸무게만 고려하면 됨

코드


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class 피자배달거리DFS {
	
	static int[] combi; //경우의 수를 채울 배열
	
	static List<Point> hs = new ArrayList<피자배달거리DFS.Point>();
	static List<Point> pz = new ArrayList<피자배달거리DFS.Point>();
	
	static int answer = Integer.MAX_VALUE;
	static int len,n,m;
	
	public static void main(String[] args) {
		피자배달거리DFS T = new 피자배달거리DFS();
		n = 4; //2차원 배열 크기
		m = 4; // 피자 집 선택 수
		int[][] board =  
			{{0, 1, 2, 0}
			,{1, 0, 2, 1}
			,{0, 2, 1, 2}
			,{2, 0, 1, 2}};
		
		for (int i = 0; i < board.length; i++) {
			for (int j = 0; j < board[i].length; j++) {
				if(board[i][j]==2) { // 피자집은 2
					pz.add(new Point(i, j));
				}else if(board[i][j]==1) {// 가정집 1
					hs.add(new Point(i, j));
				}//이외는 빈 곳
			}
		}
		len = pz.size();
		combi = new int[m];//경우의 수 배열 
		
		T.DFS(0,0);
		System.out.println(answer);
		
	}
	
	//재귀는 피자집 기준으로 쌓고 있다.
	void DFS(int L, int s) {
		if(L==m) { // 경우의 수 다 채움
			System.out.println(Arrays.toString(combi));
			int sum = 0;
			for(Point h : hs) {
				int dis = Integer.MAX_VALUE;
				//다 찬 경우의 수 배열에는 피자집 위치 정보가 있다.
				for(int i : combi) {
					dis = Math.min(dis, Math.abs(h.x-pz.get(i).x)+Math.abs(h.y-pz.get(i).y)) ;
				}
				sum += dis;
			}
			answer = Math.min(answer, sum);
		} else {
			for (int i = s; i < len; i++) {
				combi[L] = i;
				DFS(L+1, i+1);
			}
		}
	}
	
	static class Point{
		int x;
		int y;
		public Point(int x, int y) {
			super();
			this.x = x;
			this.y = y;
		}
	}
}

결과

[0, 1, 2, 3]
[0, 1, 2, 4]
[0, 1, 2, 5]
[0, 1, 3, 4]
[0, 1, 3, 5]
[0, 1, 4, 5]
[0, 2, 3, 4]
[0, 2, 3, 5]
[0, 2, 4, 5]
[0, 3, 4, 5]
[1, 2, 3, 4]
[1, 2, 3, 5]
[1, 2, 4, 5]
[1, 3, 4, 5]
[2, 3, 4, 5]
6

 

핵심은 사전처리로 피자 가게와 가정집 위치를 수집해 두 개 집단으로 묶는다.

이후 두 집단간에 DFS로 경우의 수를 구한다.

나머지는 부차적인 코드로 문제로 공식을 알려준다.

 

'자료구조&알고리즘 > 자바(Java) 알고리즘 문제풀이 : 코딩테스트 대비' 카테고리의 다른 글

다익스트라 알고리즘  (0) 2023.04.22
씨름선수  (0) 2023.04.07
섬나라아일랜드BFS  (0) 2023.04.03
섬나라아일랜드  (0) 2023.04.01
토마토BFS활용  (0) 2023.03.30

+ Recent posts