Skip to content

Commit 02e085f

Browse files
authored
Create find-the-longest-valid-obstacle-course-at-each-position.py
1 parent 48f6b4e commit 02e085f

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Time: O(nlogn)
2+
# Space: O(n)
3+
4+
import bisect
5+
6+
7+
# binary search solution
8+
class Solution(object):
9+
def longestObstacleCourseAtEachPosition(self, obstacles):
10+
"""
11+
:type obstacles: List[int]
12+
:rtype: List[int]
13+
"""
14+
result, stk = [], []
15+
for x in obstacles:
16+
i = bisect.bisect_right(stk, x)
17+
result.append(i+1)
18+
if i == len(stk):
19+
stk.append(0)
20+
stk[i] = x
21+
return result
22+
23+
24+
# Range Maximum Query
25+
class SegmentTree(object): # 0-based index
26+
def __init__(self, N,
27+
build_fn=lambda x, y: [y]*(2*x),
28+
query_fn=lambda x, y: y if x is None else max(x, y), # (lambda x, y: y if x is None else min(x, y))
29+
update_fn=lambda x, y: y,
30+
default_val=0):
31+
self.N = N
32+
self.H = (N-1).bit_length()
33+
self.query_fn = query_fn
34+
self.update_fn = update_fn
35+
self.default_val = default_val
36+
self.tree = build_fn(N, default_val)
37+
self.lazy = [None]*N
38+
39+
def __apply(self, x, val):
40+
self.tree[x] = self.update_fn(self.tree[x], val)
41+
if x < self.N:
42+
self.lazy[x] = self.update_fn(self.lazy[x], val)
43+
44+
def update(self, L, R, h): # Time: O(logN), Space: O(N)
45+
def pull(x):
46+
while x > 1:
47+
x //= 2
48+
self.tree[x] = self.query_fn(self.tree[x*2], self.tree[x*2+1])
49+
if self.lazy[x] is not None:
50+
self.tree[x] = self.update_fn(self.tree[x], self.lazy[x])
51+
52+
L += self.N
53+
R += self.N
54+
L0, R0 = L, R
55+
while L <= R:
56+
if L & 1: # is right child
57+
self.__apply(L, h)
58+
L += 1
59+
if R & 1 == 0: # is left child
60+
self.__apply(R, h)
61+
R -= 1
62+
L //= 2
63+
R //= 2
64+
pull(L0)
65+
pull(R0)
66+
67+
def query(self, L, R): # Time: O(logN), Space: O(N)
68+
def push(x):
69+
n = 2**self.H
70+
while n != 1:
71+
y = x // n
72+
if self.lazy[y] is not None:
73+
self.__apply(y*2, self.lazy[y])
74+
self.__apply(y*2 + 1, self.lazy[y])
75+
self.lazy[y] = None
76+
n //= 2
77+
78+
result = None
79+
if L > R:
80+
return result
81+
82+
L += self.N
83+
R += self.N
84+
push(L)
85+
push(R)
86+
while L <= R:
87+
if L & 1: # is right child
88+
result = self.query_fn(result, self.tree[L])
89+
L += 1
90+
if R & 1 == 0: # is left child
91+
result = self.query_fn(result, self.tree[R])
92+
R -= 1
93+
L //= 2
94+
R //= 2
95+
return result
96+
97+
def __str__(self):
98+
showList = []
99+
for i in xrange(self.N):
100+
showList.append(self.query(i, i))
101+
return ",".join(map(str, showList))
102+
103+
104+
# Time: O(nlogn)
105+
# Space: O(n)
106+
# segment tree solution
107+
class Solution2_TLE(object):
108+
def longestObstacleCourseAtEachPosition(self, obstacles):
109+
"""
110+
:type obstacles: List[int]
111+
:rtype: List[int]
112+
"""
113+
sorted_obstacles = sorted(set(obstacles))
114+
lookup = {x:i for i, x in enumerate(sorted_obstacles)}
115+
segment_tree = SegmentTree(len(lookup))
116+
result = []
117+
for x in obstacles:
118+
cnt = segment_tree.query(0, lookup[x])+1
119+
result.append(cnt)
120+
segment_tree.update(lookup[x], lookup[x], cnt)
121+
return result

0 commit comments

Comments
 (0)