LeetCode 45.跳跃游戏 II (DP+线段树)

题目地址

https://leetcode-cn.com/problems/jump-game-ii/

解题

题目咋一看可以用动态规划来做, 第i个位置到终点的位置f(i) = min(f(i+1),f(i+2)...f(k)) + 1 其中f(n-1) = 0, i 从 n-2 -> 0。这样的时间复杂度O(N^2), 数据量一大就不行了, 例如: [9999,9999,....9999]十万个9999
不过只要稍微优化一下就能达到很好的效果, 上面的解法很多时间是花在求[i,k]区间内的最小值, 这里我们可以利用线段树高效求解, 线段树每次插入, 查询花费O(logN), 优化后时间复杂度为O(NlogN) 可以轻松应对大型测试用例了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Solution:
def jump(self, nums):
"""
:type nums: List[int]
:rtype: int
"""

n = len(nums)
self.init(n)
self.update(n-1, 0)
for i in range(n-2, -1, -1):
a = i + 1
b = i + nums[i] + 1
if b > n:
b = n
p = self.query(a, b, 0, 0, self.n) + 1
self.update(i, p)

return self.query(0, 1, 0, 0, self.n)

def init(self, n):
self.INT_MAX = n
self.n = 1

while self.n < n:
self.n *= 2

self.dat = [self.INT_MAX for i in range(2 * self.n - 1)]

def update(self, k, a):
k += self.n - 1
self.dat[k] = a
while k > 0:
k = (k - 1) // 2
self.dat[k] = min(self.dat[k * 2 + 1],self.dat[k * 2 + 2])

def query(self, a, b, k, l, r):
if r <= a or b <= l:
return self.INT_MAX

if a <= l and r <= b:
return self.dat[k]
else:
vl = self.query(a, b, k * 2 + 1, l, (l + r) // 2)
vr = self.query(a, b, k * 2 + 2, (l + r) // 2, r)
return min(vl, vr)

print(Solution().jump([2, 3, 1, 1, 4]))