이번 문제는 백준의 골드 4 문제 여왕벌 문제이다.
문제를 한 번 차근차근 읽어보도록 하자.
가로세로가 최대 700
칸인 벌집이 주어진다.
매일 애벌레가 자라는 정도가 주어지며, 최대 1,000,000
일까지 주어진다.
0 1 2
를 자라는 정도로, 3 종류의 값이 주어진다.
예를 들어 1 2 2
는 0, 1, 1, 2, 2
가 되는 것이다.
주어진 일 수 만큼 자라는 정도가 주어지게 된다.
이 때 문제의 규칙대로 애벌레가 모두 자랐을 때의 결과를 출력하라.
규칙은 아래와 같다.
가장 왼쪽 열과 가장 위 행이 먼저 자란 뒤, 나머지가 자란다.
나머지는 좌, 상, 좌상
중 가장 큰 성장 값에 따라 자란다.
문제를 어떻게 해결할 수 있을까?
구현
내 생각에는 단순한 구현 문제로 보인다.
하지만 최대 일 수가 1,000,000
인 것을 보아하니, 효율성이 문제가 될 것같다.
나는 먼저 아래와 같은 코드로, 단순히 구현해 보았다.
당연히 시간초과가 발생했다. 시간복잡도를 계산해보자.
가장 먼저 자라는 애벌레들을 키우는 것은 O(2N-1)
밖에 걸리지 않는다.
하지만 문제는 이후 남은 애벌레들을 키우는 것이다.
현재 나는 이중 for
문을 사용했으니, O(N^2)
이 될 것이다.
이게 만약 일 수가 늘어나 1,000,000
일에 대해 진행한다고 가정하면,
1,000,000 * 700 * 700
은 약 5억
정도가 되는 값이다.
즉, O(N^2)
으로는 이 문제를 절대 해결할 수 없다!
그럼 O(nlogn)
으로는 가능할까?
log700
은 약 2.845
가 되므로, 700 * log700
은 약 1992
이다.
1,000,000
에 곱하게 되면, 약 2억
에 달하는 결과가 나온다.
그럼 남은 애벌레를 키우는 경우는 O(N)
만에 끝내야 한다는 결론에 다다른다.
남은 애벌레를 한 번에 계산하기
생각해보니 너무 바보같이 로직을 작성했다.
남은 애벌레를 성장시키는 로직은 생각해보면, 마지막에 한 번만 계산하면 된다.
그 이유가 뭘까?
기본적으로 성장세는 증가하기만 하도록 주어진다고 했다.
그럼 자연스럽게 좌, 좌상, 상
중에 상
이 가장 성장세가 클 것이다.
그럼 모든 날에 대한 성장세를 더한 뒤 마지막에 상
의 성장세만 더해주면?
결국은 매번 더한 것과 동일한 결과가 나올 것이다.
아래와 같이 로직을 수정했다.
하지만 안타깝게도 83점을 받게 되었다.
83점을 받았다는 것은, 마지막 문항인 4번
에서 시간 초과가 발생한 것이다.
어디서 시간을 더 줄일 수 있을까?
누적 합
결론부터 말하자면, 누적 합을 이용해 O(N)
만에 풀 수 있다.
아무리 고민해도 도저히 생각이 나지 않아, 풀이를 참고하게 됐다.
당연히 배열을 2차원으로 선언해 풀 생각만 했는데, 머리가 띵 했다.
왜 O(N)
인 1차원 배열로도 풀 수 있을까?
위에서 내가 언급했던 대로, 상
방향의 성장세만 알고 있으면 되는게 핵심이다.
남은 애벌레들의 상
방향의 성장세만 고른다고 생각을 해보자.
그럼 자연스럽게 아래와 같은 표가 됨을 알 수 있다.
위의 표를 살펴보면, 가장 첫 열을 제외한 가장 첫 행의 값들이 그대로 내려온다.
그렇다. 상
방향의 성장세만 고르면, 어차피 모두 같은 값이 내려가게 된다.
따라서 아래와 같이 코드를 수정할 수 있다.
1차원 배열을 700 * 2 - 1
크기로 선언한다.
즉 성장세를 가장 처음 저장할 꺾쇠 모양의 칸만 남기는 것이다.
이후, 주어지는 성장세에 맞춰 꺾쇠 모양의 칸을 채운다.
마지막으로 출력시에, 가장 첫 열은 따로 출력하도록 한다.
나머지 열들은 모두 각각 같은 값을 같게되니, 그냥 반복 출력하면 된다!
구현 문제를 풀 때 이렇게 효율적인 아이디어를 생각하는 게 어렵다.
좀 더 연습을 통해 사고력을 기르도록 하자.