문제 출처 : https://leetcode.com/problems/jump-game/description/
이번 문제는 음이 아닌 정수들의 array가 주어졌을 때, index 0부터 시작해서 해당 index의 값만큼 오른쪽으로 jump할 수 있습니다. 그렇게 해서 array의 끝까지 jump할 수 있는지의 여부를 리턴하는 함수를 짜는 것이 문제입니다.
예를 들면, A = [2,3,1,1,4]
가 주어졌을 때, 처음에서 점프할 수 있는 한도는 2이므로, 2만큼 점프해도 되고, 1만큼 점프해도 됩니다. 2만큼 점프했을 때는 3번째 원소로 가고, 거기서 다시 1만큼 점프해서 4번째 원소로 가고, 거기서 다시 1만큼 점프해서 마지막 원소로 갈 수 있습니다. 또한 맨 처음에서 1만큼 점프할 경우 두번째 원소로 가게 되고, 그 값이 3이므로 3칸까지 오른쪽으로 갈 수 있습니다. 이 때도 마찬가지로 마지막 원소까지 갈 수 있습니다. 따라서 이 경우엔 true
를 리턴합니다.
반면, A = [3,2,1,0,4]
이라면, 첫 원소에서 3칸까지 점프할 수 있는데, 3칸을 뛰면 거기에 있는 원소가 0이므로 더 점프할 수 없게 되고 마지막 원소로 도달할 수 없습니다. 2칸을 점프하면 1이 나오는데, 1칸 더 뛰어서 다시 0이 나오므로 마찬가지로 도달할 수 없습니다. 1칸을 점프하면 2가 나오는데, 거기서 2칸을 뛰건 1칸을 뛰건 무조건 0을 만나게 되므로 이 경우에도 마지막까지 도달할 수 없게 됩니다. 따라서 이 경우엔 결코 마지막 원소까지 점프할 수 없게됩니다! 따라서 false
를 리턴합니다.
일단 Brute force하게는 index 0에서 해당 원소만큼 모든 가능한 점프들을 해보고 그 다음 도착한 칸에서 또 가능한 모든 점프들을 해보는 식으로 구할 수 있습니다. 하지만 이는 굉장히 비효율적인 답안 찾기가 됩니다.
따라서 좀 더 효율적인 방법을 써야 하는데, 이 경우에 있어서는 greedy 알고리즘이 매우 효율적입니다.
Greedy 알고리즘의 로직은 다음과 같습니다.
1. 맨 마지막에서 두번째 index부터 0번째 index까지 오면서 조사를 시작합니다. 2. 만약nums[i]+i
가 마지막 index보다 크거나 같으면,left_most_good_index
를 i로 세팅합니다. 3. 그 후,nums[i]+i
가left_most_good_index
보다 큰 경우, 계속하여left_most_good_index
를 i로 세팅합니다.
이런 식으로 맨 첫번째 index까지 왔을 때, left_most_good_index
가 0인지 아닌지만 리턴하면 됩니다. 이렇게 되면 complexity는 이 될 것이고, memory도 그냥 variable 1개만 유지하기 때문에 의 훌륭한 optimized code가 완성됩니다! 🙂
def canJump(self, nums): | |
""" | |
:type nums: List[int] | |
:rtype: bool | |
""" | |
if len(nums) == 1: | |
return True | |
left_most_good_index = None | |
for i in xrange(len(nums)-2, -1, -1): | |
if nums[i] + i >= len(nums)-1: | |
left_most_good_index = i | |
if left_most_good_index and nums[i] + i >= left_most_good_index: | |
left_most_good_index = i | |
return left_most_good_index == 0 |