Skip to content

Commit 3e7c0f7

Browse files
solution and notes for problem 2751
1 parent 4015fba commit 3e7c0f7

File tree

1 file changed

+86
-2
lines changed

1 file changed

+86
-2
lines changed

problems/2751/paxtonfitzpatrick.md

+86-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,94 @@
22

33
## Initial thoughts (stream-of-consciousness)
44

5+
- all robots are moving at the same speed, so any moving in same direction can't collide
6+
- if all characters in `directions` are the same, can just return `healths`
7+
- also, any moving away from each other won't collide
8+
- after filtering for same direction, can filter remaining opposite-direction movers for instances where one moving `R` has a larger `directions` value than another moving `L`.
9+
- this feels complex enough that I think it might be worth writing a `Robot` class to track attributes for each robot
10+
- order in which collisions happens will be important, because removed robot then won't collide with subsequent ones it would've otherwise encountered
11+
- maybe this means I'll want to simulate this in terms "timesteps" so I can make sure to execute collision logic in the right order
12+
- though simulation solutions are rarely the most optimal, and it seems like leetcode usually includes a test case that'd cause simulation-based solutions to time out
13+
- I think the scenario where a simulation would be bad is if the colloding robots start very far from each other, causing me to have to simulate a bunch of noop timesteps (and check whether any robots are in the same location for each of them) before something actually happens. But I think I can avoid this by -- at each timestep where a collision happens, as well as the first -- finding the minimum distance between collision-eligible pair of robots and immediately advancing time by that many steps.
14+
- instead of simulating individual timesteps, could I figure this out from the initial positions and direction of the robots?
15+
- I think so, if I start with the rightmost robot moving right and collide it with further-right robots that're moving left until it's dead... at which point I could move onto the next-rightmost right-moving robot and collide it with further-right left-moving robots
16+
- Would this work with a scenario like example 3, where there are two indepenedent, simultaneous collisions?
17+
- collide robot 3 with robot 4
18+
- if it survives, we know it'll be in the returned array and we can move onto robot 1
19+
- if it dies, we also move onto robot 1
20+
- in either case, next move onto robot 1, collide it with robot 2
21+
- if it survives
22+
- if robot 4 survived the robot 3 vs 4 collision
23+
- collide robot 1 with robot 4
24+
- the survivor will be in the returned array
25+
- if robot 3 survived the robot 3 vs 4 collision
26+
- robot 1 will be in the returned array
27+
- if it dies, robot 2 *and* robot 4 will be in the returned array
28+
- I *think* this will work... I think I'll just need 2 separate lists(?) to keep track of right-moving and left-moving robots independently, so I can figure out which to collide with which
29+
- also, both will need to be sorted so I can access the "next" robot from each list correctly
30+
- I'd need to loop over robots to construct those two list anyway... if I pre-sort the initial list of robots moving in both directions, can I just do the collisions at the same time?
31+
- this feels like it's trying to get me to use a stack... or two?
32+
- let's say I get the list of robots in position order (I'll figure out how later). Then I could:
33+
- create a stack for right-moving robots (and one for left-moving robots?)
34+
- for each robot
35+
- if it's moving right, push it onto a stack of right-moving robots
36+
- this means the stack will also be in order of position, with the rightmost right-moving robot on top... yeah this definitely feels like how they're trying to get me to solve it... I think
37+
- else (it's moving left), check whether there are any right-moving robots on the stack
38+
- if there aren't, we know that robot is a survivor, and can move onto the next robot in the list
39+
- else (there are) collide it with the right-moving robot on top of the stack
40+
- if the left-moving robot survives, pop the right-moving robot off the stack (can discard because we know it didn't survive) and collide the left-moving robot with the new top-most right-moving robot, and so on
41+
- (I think this means I'll actually need to use a `while` loop for checking whether there are robots in the stack instead of `if`/`else`)
42+
- else (the right-moving robot survived) move onto the next robot in the sorted list and repeat
43+
- ah, also need to account for equal health -- neither survives in that case
44+
- any robots on the stack when we get to the end of the list are survivors
45+
- also, seems like I *won't* need a separate stack for left-moving robots
46+
- how do i get the survivor list back into the right order?
47+
- if I create a bunch of `Robot` objects, I could initialize them with an attr for their original index, and then sort the survivor list by `key=lambda robot: robot.<that_attr>`
48+
- but the constraints say there can be up to $10^5$ robots, so creating that many objects -- even small, optimized ones with `namedtuple` or `dataclass` -- would take a ton of memory and also initialization time...
49+
- what value do I keep track of in the stack of right-moving robots if I'm not using `Robot` objects though?
50+
- could I create some sort of mapping between the robots' pre- and post-sorting indices?
51+
- `np.argsort` would be nice here... alas
52+
- could I create the equivalent output some other way?
53+
- I could create a list of indices, and then sort that according to `positions` without *actually* sorting positions... then instead of sorting `positions` in the first place and mapping thos indices onto `healths`, `directions` , then trying to map backwards, I could use the sorted list of indices to get the next index from all 3 input lists for the current iteration.
54+
- ooo important note with this though -- I wouldn't want to actually remove any defeated robots from any of the lists while iterating, because that would mess up the mapping. Also, once I determine the "current" robot is a survivor, I can't just append them to the list I'll eventually return because I'm iterating in sorted order and not input order.
55+
- *But* all the input lists are still in their original order, including `healths`, which is the basis for the values I need to return... so I could just modify `healths` in-place and return that at the end.
56+
- I'd have to filter 0's to remove defeated robots before returning it... which ultimately means another loop, so this might just be a wash. But it's the idea I have right now so I'll go with it...
57+
558
## Refining the problem, round 2 thoughts
659

760
## Attempted solution(s)
61+
862
```python
9-
class Solution: # paste your code here!
10-
...
63+
class Solution:
64+
def survivedRobotsHealths(self, positions: List[int], healths: List[int], directions: str) -> List[int]:
65+
sorted_ixs = list(range(len(positions)))
66+
sorted_ixs.sort(key=lambda i: positions[i])
67+
right_movers_stack = []
68+
69+
for curr_ix in sorted_ixs:
70+
if directions[curr_ix] == 'R':
71+
right_movers_stack.append(curr_ix)
72+
else:
73+
while len(right_movers_stack) > 0:
74+
rightmost_right_mover_ix = right_movers_stack[-1]
75+
rightmost_right_mover_health = healths[rightmost_right_mover_ix]
76+
if rightmost_right_mover_health > healths[curr_ix]:
77+
healths[curr_ix] = 0
78+
healths[rightmost_right_mover_ix] -= 1
79+
break
80+
elif rightmost_right_mover_health == healths[curr_ix]:
81+
healths[curr_ix] = 0
82+
healths[rightmost_right_mover_ix] = 0
83+
right_movers_stack.pop()
84+
break
85+
else:
86+
right_movers_stack.pop()
87+
healths[rightmost_right_mover_ix] = 0
88+
healths[curr_ix] -= 1
89+
90+
return list(filter(None, healths))
1191
```
92+
93+
![](https://github.com/user-attachments/assets/8a60614f-f696-4922-8308-887508c6f70c)
94+
95+
yay!

0 commit comments

Comments
 (0)