오늘은 하루 종일 열심히 강의를 들었다. 스프링 심화 강의는 이전 강의들과 다르게 난이도가 상당했다. 복습하면서 이것저것 찾아볼 것도 많이 생길 것 같다.
여기에는 오늘 오전에 풀었던 알고리즘 문제 풀이 과정을 정리해보았다.
1. 알고리즘 문제 풀이
프로그래머스에 있는 '다리를 지나는 트럭' 문제를 풀어보았다.
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 |
1-2. 문제 풀이
문제를 보자마자 큐를 이용해서 문제를 풀어야 겠다라는 생각은 바로 들었는데(문제 분류도 스택/큐로 되어있다), 어떻게 큐를 이용해서 문제를 풀어야하는지가 감을 잡지 못해 한참 고생했었다.
트럭을 최대 무게가 초과되지 않을 때까지 차례로 큐에 쌓고, 무게의 합에 따라 빼고 넣고를 반복하면 된다는 것 까지는 알았고 코드의 전체 구조는 잡아놓았다.
그런데 시간이 1초 지났다는 것을 어떻게 코드로 작성(표현?)해야 할지 감을 잡지 못했다. Map 같은 것을 이용해야하나 생각도 했었다.
시간이 한참 지나도 생각이 나지 않아서 다른 사람들의 아이디어를 찾아보게 되었고, 보자마자 아차 싶었다. 큐에 0을 넣는 것으로 1초 시간이 지났음을 간단하게 표현할 수 있다는 것을 알게된 것이었다.
큐에 0을 집어넣으면, 큐의 총합을 구할 때 합산되지 않고, 큐에 공간을 차지할 수 있다. 큐를 현재 트럭이 다리 위에 올라와 있는 상황을 표현한다고 그림을 그려보면 이해하기 쉽다. 0이 들어간 곳은 트럭이 없는 빈 공간인 것이다.
대기 중인 트럭이 다리에 올라갈 수 있으면 큐에 그 숫자를 더해주면 되고, 그렇지 않다면 0을 더해주면 된다. 그러다가 큐의 크기와 다리의 길이가 같아지는 순간 처음 큐에 들어온 요소를 빼주고, 트럭이나 0을 더해주면 된다.
그렇게 답안을 작성했더니 잘 작동했고, 답안으로 통과과 되었다. 그렇지만 실행속도가 조금 오래걸리는 것 같아 조금 더 수정해 보았다.
원래는 다리 위에 올라가 있는 트럭들의 무게를 따로 변수로 선언해두지 않고, bridge.sum()으로 스택 안의 값들의 총 합을 구해줬었는데 이렇게 하면 매번 스택을 모두 돌면서 합을 구해야하기 때문에 매우 비효율적이다. 그래서 totalWeight 라고 변수를 하나 만들어줘서 합을 구하도록 했다. 그랬더니 실행 속도를 어느정도 줄일 수 있었다.
아래가 그렇게 작성한 최종 답안 코드이다.
class Solution {
fun solution(bridge_length: Int, weight: Int, truck_weights: IntArray): Int {
var answer = 0
val bridge = ArrayDeque<Int>()
var totalWeight = 0
for (truck in truck_weights) {
while (true) {
// 다리가 비어있을 경우 트럭을 올리고, 다리 위의 총 무게를 더한 뒤, 시간을 1초 더해준다
if (bridge.isEmpty()) {
bridge.add(truck)
totalWeight += truck
answer += 1
break
/* 다리 위에 올라와 있는 트럭 개수와 다리 길이가 같다면 맨 처음 다리에 올라온
트럭을 내려준다. 그리고 총 무게에서 트럭 무게를 빼준다 */
} else if (bridge.size == bridge_length) {
totalWeight -= bridge.removeFirst()
} else {
/* 만약 현재 다리 위의 트럭들의 무게와 올리려고 하는 트럭 무게의 합이
다리 위에 올릴 수 있는 최대 무게보다 크다면, 스택에 0을 더해주고 시간도 1초 더해준다
그렇지 않다면, 트럭을 다리에 올리고, 시간도 1초 더해준다
*/
if (totalWeight + truck > weight) {
bridge.add(0)
answer += 1
} else {
bridge.add(truck)
totalWeight += truck
answer += 1
break
}
}
}
}
// 모든 트럭을 다리위에 올린 뒤에 다리 길이 만큼 더해줘야 최종 걸린 시간을 구할 수 있다
answer += bridge_length
return answer
}
}
2. 오늘 배운 것
- QueryDsl 설정, 사용법을 배웠다. SQL에 익숙하기 때문에 사용법을 익히는데 큰 어려움은 없을 것 같다.
- 스프링 시큐리티 강의를 다 들었다. 앞으로 반복해서 여러 번 보게 될 것 같다...
'오늘 배운 것' 카테고리의 다른 글
24-06-07 알고리즘 문제 풀이 (0) | 2024.06.07 |
---|---|
24-06-06 Spring 설정 값 주입하기 (0) | 2024.06.06 |
24-06-04 JPA @MappedSuperClass (0) | 2024.06.04 |
24-06-03 팀 프로젝트 회고 (0) | 2024.06.03 |
24-06-02 정규 표현식 작성하기 (0) | 2024.06.02 |