-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathjump_game.rs
More file actions
274 lines (218 loc) · 6.85 KB
/
Copy pathjump_game.rs
File metadata and controls
274 lines (218 loc) · 6.85 KB
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*
* 跳跃游戏 - 使用贪心判断能否到达最后一个下标
*
* 算法:
* - 给定一个数组,每个元素表示当前位置最大可跳跃步数
* - 判断是否可以到达最后一个下标
* - 贪心策略:维护当前能到达的最远位置
*
* 时间复杂度:O(n)(单次遍历)
* 空间复杂度:O(1)(不计输出)
*/
#[derive(Debug)]
struct JumpGameAnalysis {
can_reach: bool,
min_jumps: i32,
path: Vec<usize>,
}
impl std::fmt::Display for JumpGameAnalysis {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Can reach: {}, Min jumps: {}, Path: {:?}",
self.can_reach, self.min_jumps, self.path
)
}
}
// 判断是否能到达数组的最后一个下标
fn can_jump(nums: &[usize]) -> bool {
if nums.is_empty() || nums.len() == 1 {
return true;
}
let mut max_reach = 0;
for (i, &num) in nums.iter().enumerate() {
// 如果当前位置超过了最远可达位置,则无法继续前进,返回 false
if i > max_reach {
return false;
}
// 更新当前能到达的最远位置
max_reach = max_reach.max(i + num);
// 提前结束:一旦可以到达末尾,立刻返回 true
if max_reach >= nums.len() - 1 {
return true;
}
}
max_reach >= nums.len() - 1
}
// 计算到达最后一个下标所需的最少跳跃次数
fn min_jumps(nums: &[usize]) -> i32 {
if nums.is_empty() || nums.len() == 1 {
return 0;
}
// 先检查是否可以到达终点
let mut max_reach = 0;
for (i, &num) in nums[..nums.len() - 1].iter().enumerate() {
if i > max_reach {
return -1;
}
max_reach = max_reach.max(i + num);
}
if max_reach < nums.len() - 1 {
return -1;
}
// 使用贪心策略计算最少跳跃次数
let mut jumps = 0;
let mut current_end = 0;
let mut farthest = 0;
// 遍历数组,计算最少跳跃次数
for (i, &num) in nums[..nums.len() - 1].iter().enumerate() {
// 更新当前能到达的最远位置
farthest = farthest.max(i + num);
// 如果当前位置等于当前结束位置,则跳跃次数加1,并更新当前结束位置
if i == current_end {
jumps += 1;
current_end = farthest;
}
}
jumps
}
// 构造从起点到终点的一条跳跃路径
fn jump_path(nums: &[usize]) -> Vec<usize> {
if nums.is_empty() {
return vec![];
}
if nums.len() == 1 {
return vec![0];
}
// 先检查是否可以到达终点
let mut max_reach = 0;
for (i, &num) in nums.iter().enumerate() {
if i > max_reach {
return vec![];
}
max_reach = max_reach.max(i + num);
if max_reach >= nums.len() - 1 {
break;
}
}
if max_reach < nums.len() - 1 {
return vec![];
}
// 贪心构造路径
let mut path = vec![0];
let mut current_pos = 0;
// 遍历数组,构造跳跃路径
while current_pos < nums.len() - 1 {
// 初始化下一个位置为当前位置
let mut next_pos = current_pos;
// 初始化下一个位置能到达的最远位置为当前位置能到达的最远位置
let mut max_next_reach = current_pos + nums[current_pos];
// 遍历当前位置能到达的范围内,找到能到达的最远位置
for i in (current_pos + 1)..=(current_pos + nums[current_pos]).min(nums.len() - 1) {
// 如果当前位置能到达的最远位置小于当前位置能到达的最远位置,则更新当前位置能到达的最远位置
if i + nums[i] > max_next_reach {
max_next_reach = i + nums[i];
next_pos = i;
}
}
if next_pos == current_pos {
return vec![];
}
path.push(next_pos);
current_pos = next_pos;
}
path
}
// 综合分析跳跃游戏问题
fn analyze_jump_game(nums: &[usize]) -> JumpGameAnalysis {
JumpGameAnalysis {
can_reach: can_jump(nums),
min_jumps: min_jumps(nums),
path: jump_path(nums),
}
}
fn test_basic_reachable() {
println!("\n[Test 1] Reachable - should return true");
let nums = vec![2, 3, 1, 1, 4];
let analysis = analyze_jump_game(&nums);
println!("Input: {:?}", nums);
println!("{}", analysis);
}
fn test_not_reachable() {
println!("\n[Test 2] Not reachable - should return false");
let nums = vec![3, 2, 1, 0, 4];
let result = can_jump(&nums);
println!("Input: {:?}", nums);
println!("Can reach end: {}", result);
}
fn test_single_element() {
println!("\n[Test 3] Single element");
let nums = vec![0];
let result = can_jump(&nums);
println!("Input: {:?}", nums);
println!("Can reach end: {}", result);
}
fn test_zero_jump() {
println!("\n[Test 4] All zeros except last");
let nums = vec![0, 1];
let result = can_jump(&nums);
println!("Input: {:?}", nums);
println!("Can reach end: {}", result);
}
fn test_large_jumps() {
println!("\n[Test 5] Large jumps available");
let nums = vec![10, 0, 0, 0, 0];
let analysis = analyze_jump_game(&nums);
println!("Input: {:?}", nums);
println!("{}", analysis);
}
fn test_multiple_jumps() {
println!("\n[Test 6] Requires multiple jumps");
let nums = vec![2, 3, 1, 1, 1];
let analysis = analyze_jump_game(&nums);
println!("Input: {:?}", nums);
println!("{}", analysis);
}
fn test_blocked() {
println!("\n[Test 7] Blocked at second-to-last");
let nums = vec![1, 0, 1, 0];
let result = can_jump(&nums);
println!("Input: {:?}", nums);
println!("Can reach end: {}", result);
}
fn test_two_element() {
println!("\n[Test 8] Two element array");
let nums = vec![2, 3];
let analysis = analyze_jump_game(&nums);
println!("Input: {:?}", nums);
println!("{}", analysis);
}
fn test_decreasing() {
println!("\n[Test 9] Large array with decreasing values");
let nums = vec![5, 4, 3, 2, 1, 0];
let analysis = analyze_jump_game(&nums);
println!("Input: {:?}", nums);
println!("{}", analysis);
}
fn test_complex() {
println!("\n[Test 10] Complex reachable scenario");
let nums = vec![2, 5, 0, 0];
let analysis = analyze_jump_game(&nums);
println!("Input: {:?}", nums);
println!("{}", analysis);
}
fn main() {
println!("==================================================");
println!("JUMP GAME - Greedy Approach (Rust)");
println!("==================================================");
test_basic_reachable();
test_not_reachable();
test_single_element();
test_zero_jump();
test_large_jumps();
test_multiple_jumps();
test_blocked();
test_two_element();
test_decreasing();
test_complex();
}