Skip to content

Commit a658e59

Browse files
committed
Runtime: 100 ms (Top 85.48%) | Memory: 18.80 MB (Top 11.29%)
1 parent 70d783f commit a658e59

File tree

1 file changed

+91
-36
lines changed

1 file changed

+91
-36
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,95 @@
1+
// Runtime: 100 ms (Top 85.48%) | Memory: 18.80 MB (Top 11.29%)
2+
13
class Solution:
2-
def numMovesStonesII(self, stones: list[int]) -> list[int]:
3-
"""
4-
1. For the higher bound, it is determined by either moving the leftmost
5-
to the right side, or by moving the rightmost to the left side:
6-
1.1 If moving leftmost to the right side, the available moving
7-
positions are A[n - 1] - A[1] + 1 - (n - 1) =
8-
A[n - 1] - A[1] - n + 2
9-
1.2 If moving rightmost to the left side, the available moving
10-
positions are A[n - 2] - A[0] + 1 - (n - 1) =
11-
A[n - 2] - A[0] - n + 2.
12-
2. For the lower bound, we could use sliding window to find a window
13-
that contains the most consecutive stones (A[i] - A[i - 1] = 1):
14-
2.1 Generally the moves we need are the same as the number of
15-
missing stones in the current window.
16-
2.3 When the window is already consecutive and contains all the
17-
n - 1 stones, we need at least 2 steps to move the last stone
18-
into the current window. For example, 1,2,3,4,10:
19-
2.3.1 We need to move 1 to 6 first as we are not allowed to
20-
move 10 to 5 as it will still be an endpoint stone.
21-
2.3.2 Then we need to move 10 to 5 and now the window becomes
22-
2,3,4,5,6.
23-
"""
24-
A, N = sorted(stones), len(stones)
25-
maxMoves = max(A[N - 1] - A[1] - N + 2, A[N - 2] - A[0] - N + 2)
26-
minMoves = N
4+
'''
5+
Test cases walk through
6+
Given 7, 4, 9 prove 1, 2 6, 5, 4, 3, 10, prove 2, 3
7+
8+
Sort stones -> 4, 7, 9 3, 4, 5, 6, 10
9+
Stone length -> 3 5
10+
Move penultimate = 7 - 4 - 3 + 2 = 2 6-3-5+2 = 0
11+
Move final = 9 - 7 - 3 + 2 = 1 10-4-5+2 = 3
12+
Neither is 0, so we cannot return for sure Move penultimate is 0, so move final is assured
13+
This means we can return [min(2, 3), 3] -> [2, 3]
14+
15+
Max legal moves is 0 For completeness, max legal moves is 0, max moves is 3
16+
starting index is 0 starting index is 0
2717
28-
# Calculate minimum moves through sliding window.
29-
start = 0
30-
for end in range(N):
31-
while A[end] - A[start] + 1 > N:
32-
start += 1
18+
Enumeration Enumeration
19+
index is 0, stone is 4 index is 0, stone is 3
20+
stones[0] lte 4 - 3 ? No, skip while loop stones[0] lte 3 - 5 ? No, skip while
21+
max legal moves is min of (max of self and 0 - 0 + 1, most moves) max legal moves is min of (max of self and 0 - 0 + 1), max moves -> max legal moves is 1
22+
-> max legal moves is 1
3323
34-
if end - start + 1 == N - 1 and A[end] - A[start] + 1 == N - 1:
35-
# Case: N - 1 stones with N - 1 positions.
36-
minMoves = min(minMoves, 2)
37-
else:
38-
minMoves = min(minMoves, N - (end - start + 1))
24+
index is 1, stone is 7 index is 1, stone is 4
25+
stones[0] <= 7 - 3 ? Yes, enter while stones[0] lte 4 - 5 ? No, skip while
26+
starting index is now 1 max legal moves is min of (max of self and 1 - 0 + 1), max moves -> max legal moves is 2
27+
stones[1] <= 7 - 3 ? No, skip while
28+
max legal moves -> min(max of self and 1 - 1 + 1), max_moves
29+
-> max legal moves is 1 index is 2, stone is 5
30+
stones[0] lte 5 - 5 ? No skip while
31+
index is 2, stone is 9 max legal moves is min of (max of self and 2 - 0 + 1), max_moves -> max legal moves is 3
32+
stones[1] <= 9 - 3 ? No, skip while
33+
max legal moves is min(max of self and 2-1 + 1), max_moves
34+
-> max legal moves is 2 index is 3, stone is 6
35+
End enumeration stones[0] lte 6 - 5 ? No skip while
36+
max legal moves is min (max of self and 3 - 0 + 1), max_moves -> max legal moves is 3
37+
Return [3 - 2, 2] -> [1, 2] checks out
38+
index is 4, stones is 10
39+
stones[0] lte 10 - 5 ? Yes, enter while
40+
starting index is 1
41+
stones[1] lte 10 - 5 ? Yes, enter while
42+
starting index is 2
43+
stones[2] lte 10 - 5 ? Yes, enter while
44+
starting index is 3
45+
max legal moves is min (max of self and 4 - 3 + 1), max moves -> max legal moves is 3
46+
End enumeration
3947
40-
return [minMoves, maxMoves]
48+
Return [5 - 3, 3] -> [2, 3]
49+
'''
50+
def numMovesStonesII(self, stones: List[int]) -> List[int] :
51+
# order does not need to be maintained, so sorting is optimal
52+
stones.sort()
53+
# want to work within stone physical space since 10^9 >> 10^4 (stone weight vs length)
54+
stone_length = len(stones)
55+
# what is the cost of moving the second to last stone and the 0th stone?
56+
move_penultimate = stones[-2] - stones[0] - stone_length + 2
57+
# what is the cost of moving the last stone and the 1st stone?
58+
move_final = stones[-1] - stones[1] - stone_length + 2
59+
# in both of these, the cost is the positional exchange in stones along the stone length + 2 for the two stones moving
60+
# our most moves possible are the max of these two
61+
most_moves = max(move_penultimate, move_final)
62+
# since the stones are unique, if either is 0, the one that we have must be max legal moves
63+
# if move penultimate is 0, that means that the second largest stone less the least stone less the length + 2 is 0
64+
# this means that the largest stone, which must be at least one larger than the largest, less the second to least stone which is at least one larger than the least stone less the length + 2 is move final
65+
# our minimal length is 3
66+
# let a, b, c be stones in order
67+
# b - a - 3 + 2 = 0 -> b = a + 1 move penultimate
68+
# c - b - 3 + 2 = 0 -> b = c - 1 move final
69+
# c - 1 = a + 1 -> c = a + 2
70+
# all stones must be at least 1 to 10^9 and are unique
71+
# so at minimum a is 1, b is 2 and c is 3
72+
# in this case, move final is also 0 so we get 0, 0
73+
# if a = 4, b = 5, c = 7
74+
# 5 - 4 - 3 + 2 = 0 move penultimate is 0
75+
# 7 - 5 - 3 + 2 -> 1 move ultimate is 1
76+
# min legal moves is min of 2 and 1 -> min legal moves is 1 -> 1, 1 is returned
77+
# from this it can be seen that the movement of c relative to b impacts the return here when one is 0, and that if either is 0 it does not preclude the other. However it does entail a relation to 2 as most that min could become
78+
# this is because if most moves is greater than 2, we could always do the move alternate that was 0 in two steps. This is what locks in to place the ability to use 2 here as the min argument.
79+
if move_penultimate == 0 or move_final == 0 :
80+
min_legal_moves = min(2, most_moves)
81+
return [min_legal_moves, most_moves]
82+
# how many legal moves are there in sorted order?
83+
max_legal_moves = 0
84+
# starting from 0th index
85+
starting_index = 0
86+
# enumerate each stone and index
87+
for index, stone in enumerate(stones) :
88+
# while the stone at starting index is lte this stone minus stone length (cost of a move)
89+
while stones[starting_index] <= stone - stone_length :
90+
# increment
91+
starting_index += 1
92+
# max legal moves is then set to maxima of self and indexed difference with 1 for 0 based indexing
93+
max_legal_moves = min(max(max_legal_moves, index - starting_index + 1), most_moves)
94+
# return length - max legal moves when in sorted order (your minimal move state) and most moves in sorted order
95+
return [stone_length - max_legal_moves, most_moves]

0 commit comments

Comments
 (0)