Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions coin-change/rivkode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
1. 문제 이해
숫자들을 조합해서 타겟 넘버를 만족하는 가장 작은 코인의 개수를 반환
만족하는 조합이 없다면 -1 반환

배열 정렬 후 작은 숫자부터 시작해서 더하며 타겟넘버와 일치하는지 체크
일치한다면 그때의 코인 개수를 기존 개수와 비교 및 초기화
만약 크다면 return 하여 다음 숫자로 이동

2. 예외 상황

output이 12가 되는 경우와 0이 되는 경우는 각각 무슨 경우일까 ?

12가 되는 경우는 어떤 조합으로도 타겟넘버를 만들지 못했을 경우

0이 되는 경우는 amount가 0일 경우 아무 숫자도 반환되면 안될 경우이므로 가장 처음 초기화 되고 바로 리턴됨.

3. 알고리즘
dfs

4. 구현
수도 코드
dfs(사용한 코인 개수, 지금까지의 값)
현재 값 == 타겟 값 체크
맞다면 최소값 초기화
반환

for coins
지금까지의 값 + 새로운 코인 <= 타겟 값
맞다면 dfs(사용한 코인 개수 + 1, 지금까지의 값 + 새로운 코인)

dp

재귀로 풀었으니 Time limit이 걸리지 않기 위해 dp로도 풀 수 있는 점을 고려할 수 있다.

dp 점화식을 만들어 보자
n 원을 만들기 위한 동전의 최소 개수이므로
n이 만들고 싶은 금액, coin이 현재 선택한 동전이라고 할때
dp[n] = min(dp[n], dp[n-coin] + 1) 이 나온다.
n-coin 이 나오게된 이유는 n을 만들기 위해 특정 숫자에서 coin 더하여 n 을 만들어야 하기 때문이다.
x + coin = n -> x = n - coin 식이 만들어 진다.
해당 n-coin 을 만들기 위한 최소값에서 coin을 더했으므로 1을 더해줌으로써
선택한 coin 에서 n 을 만들기 위한 최소 개수를 얻을 수 있기 때문이다.

*/

import java.util.*;

class Solution {
private int min;
public int coinChange(int[] coins, int amount) {
// int maxLength = 12;
// min = maxLength + 1;
// dfs(0, 0, amount, coins);
// if (min == 13) {
// return -1;
// }

int[] dp = new int[amount + 1];


for (int i=1; i<dp.length; i++) {
dp[i] = amount + 1; // 최대값보다 1을 더하여 무효한 값(최대값보다 클 수 없음)을 임의로 넣어준다.
}
dp[0] = 0;
// coin 들을 순회하며 각 코인들을 루프마다 해당 동전으로 최적화를 한다. 그래서 3번째 동전을 돌때에는 이전 1, 2번째의 동전들에 대해 누적된 결과를 얻게 된다.
for (int c : coins) {
// c 부터 시작하는 이유는 가지고 있는 코인보다 적은 n 을 만들 수 없기 때문
for (int n = c; n < amount + 1; n++) {
dp[n] = Math.min(dp[n], dp[n-c] + 1);
}
}

if (dp[amount] == amount + 1) {
return -1;
}

return dp[amount];
}


// 시간 초과 발생
// public void dfs(int count, long total, int amount, int[] coins) {
// if (total == amount) {
// min = Math.min(min, count);
// return;
// }

// for (int coin: coins) {
// if (total + coin <= amount) {
// dfs(count + 1, total + coin, amount, coins);
// }
// }
// }
}

76 changes: 76 additions & 0 deletions merge-two-sorted-lists/rivkode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
/*
1. 문제 이해
두개의 정렬된 리스트를 머지한다
이때 이미 정렬된 리스트를 합치는 것이므로 2개의 head를 비교해서 작거나 같은 것을 next로 붙이면 된다

2. 알고리즘
while 사용, 재귀

3. 예외 케이스

둘중에 하나의 리스트가 먼저 null 이 되버리면 나머지 리스트도 붙여줘야 하므로 while 문이 끝난 뒤에 붙여줘야 한다.

4. 구현
각 head를 비교해서 더 작은 것을 head 로 두고 작은것의 next와 다른 리스트의 head 를 다시 비교한다
만약 같다면 둘중 하나를 선택한다
아니다
이렇게 순서가 되어야 하지 않을까
#0 리스트1과 리스트2가 Null이 아닌지 체크한다 Null 이면 head 반환.
#1 두개의 비교할 노드를 초기화 한다
#2 두개의 값을 비교한다
#3 작은 값을 이전 Head의 Next로 정한다
#4 작은 값의 next를 다시 비교할 노드로 세팅한다
#5 2번으로 다시 돌아가서 반복한다

즉 비교할 노드를 초기화 하고
비교해서 next로 넣고
다시 초기화 해서 비교한다

예를 들어
1 - 2 - 3
3 - 4 - 5
일 경우
1이 작으므로 1을 head 로 두고
next를 구하기 위해 1의 Next와 3을 비교한다
1의 Next가 2이므로 1의 next는 2가 된다
2의 Next와 3을 다시 비교한다

답지를 보니 재귀로도 풀 수 있고 내가 한 방식으로도 풀 수 있네.

가장 앞에 dummy를 두어서 head를 세팅할 수 있다는 생각을 해야겠다.
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(-1);
ListNode node = dummy;

while (list1 != null && list2 != null) {
// 각 리스트의 값을 비교
if (list1.val < list2.val) {
node.next = list1;
list1 = list1.next;
} else {
node.next = list2;
list2 = list2.next;
}

// Node 의 커서를 다음으로 이동
node = node.next;
}

// 나머지 부분을 현재 Node 의 next를 붙여주기 위함
node.next = l1 != null ? l1 : l2;

return dummy.next;
}
}