@@ -3,11 +3,15 @@ import { AnimationTimeline } from '../state/animationSlice';
3
3
/**
4
4
* 使用动态规划算法生成爬楼梯问题的解和动画时间线
5
5
* @param n 楼梯的阶数
6
- * @returns 包含结果和动画时间线的对象
6
+ * @returns 包含结果、时间线和可视化数据的对象
7
7
*/
8
8
export function generateDPSolution ( n : number ) : {
9
9
result : number ;
10
10
timeline : AnimationTimeline [ ] ;
11
+ staircase ?: {
12
+ nodes : { id : number ; x : number ; y : number ; value : number } [ ] ;
13
+ links : { source : number ; target : number } [ ] ;
14
+ } ;
11
15
} {
12
16
// 初始化时间线
13
17
const timeline : AnimationTimeline [ ] = [ ] ;
@@ -37,14 +41,14 @@ export function generateDPSolution(n: number): {
37
41
result : 1 ,
38
42
timeline : [ {
39
43
timestamp : stepCounter ++ * 1000 ,
40
- description : "只有1阶楼梯,只有1种爬法" ,
44
+ description : "只有1阶楼梯,只有1种爬法(一次爬1阶) " ,
41
45
visualChanges : {
42
46
nodeUpdates : [
43
47
{ index : 0 , props : { x : 50 , y : 300 , value : 1 } } ,
44
48
{ index : 1 , props : { x : 150 , y : 260 , value : 1 } }
45
49
] ,
46
50
matrixUpdates : [ ] ,
47
- formulaUpdate : "n = 1,返回1 "
51
+ formulaUpdate : "f(1) = 1"
48
52
} ,
49
53
interactionPoints : [ ]
50
54
} ]
@@ -56,10 +60,46 @@ export function generateDPSolution(n: number): {
56
60
dp [ 0 ] = 1 ;
57
61
dp [ 1 ] = 1 ;
58
62
63
+ // 引入基本概念
64
+ timeline . push ( {
65
+ timestamp : stepCounter ++ * 1000 ,
66
+ description : "爬楼梯问题:每次可以爬1阶或2阶,问爬到第n阶有多少种方法?" ,
67
+ visualChanges : {
68
+ nodeUpdates : [ ] ,
69
+ matrixUpdates : [ ] ,
70
+ formulaUpdate : "动态规划解法"
71
+ } ,
72
+ interactionPoints : [ ]
73
+ } ) ;
74
+
75
+ // 解释动态规划思路
76
+ timeline . push ( {
77
+ timestamp : stepCounter ++ * 1000 ,
78
+ description : "动态规划的关键是找到状态转移方程,我们需要思考如何到达第n阶" ,
79
+ visualChanges : {
80
+ nodeUpdates : [ ] ,
81
+ matrixUpdates : [ ] ,
82
+ formulaUpdate : "f(n) = f(n-1) + f(n-2)"
83
+ } ,
84
+ interactionPoints : [ ]
85
+ } ) ;
86
+
87
+ // 解释状态转移方程
88
+ timeline . push ( {
89
+ timestamp : stepCounter ++ * 1000 ,
90
+ description : "想要到达第n阶,可以从第n-1阶爬1阶,或从第n-2阶爬2阶,所以f(n) = f(n-1) + f(n-2)" ,
91
+ visualChanges : {
92
+ nodeUpdates : [ ] ,
93
+ matrixUpdates : [ ] ,
94
+ formulaUpdate : "f(n) = f(n-1) + f(n-2)"
95
+ } ,
96
+ interactionPoints : [ ]
97
+ } ) ;
98
+
59
99
// 初始化阶段的时间线
60
100
timeline . push ( {
61
101
timestamp : stepCounter ++ * 1000 ,
62
- description : "初始化阶段,第 0 阶和第 1 阶各有 1 种爬法 " ,
102
+ description : "初始化:第0阶表示起点,有1种方法(不爬);第1阶有1种方法(爬1阶) " ,
63
103
visualChanges : {
64
104
nodeUpdates : [
65
105
{ index : 0 , props : { x : 50 , y : 300 , value : 1 } } ,
@@ -71,15 +111,37 @@ export function generateDPSolution(n: number): {
71
111
interactionPoints : [ ]
72
112
} ) ;
73
113
114
+ // 创建节点之间的连接关系
115
+ const links = [ ] ;
116
+
74
117
// 状态转移阶段
75
118
for ( let i = 2 ; i <= n ; i ++ ) {
76
119
// 计算当前阶的值
77
120
dp [ i ] = dp [ i - 1 ] + dp [ i - 2 ] ;
78
121
79
- // 添加到时间线
122
+ // 添加连接
123
+ links . push ( { source : i - 1 , target : i } ) ;
124
+ links . push ( { source : i - 2 , target : i } ) ;
125
+
126
+ // 添加到时间线 - 状态转移前的解释
127
+ timeline . push ( {
128
+ timestamp : stepCounter ++ * 1000 ,
129
+ description : `准备计算第${ i } 阶的爬法数量,需要用到第${ i - 1 } 阶和第${ i - 2 } 阶的结果` ,
130
+ visualChanges : {
131
+ nodeUpdates : [
132
+ { index : i - 1 , props : { x : 50 + ( i - 1 ) * 100 , y : 300 - Math . min ( ( i - 1 ) * 50 , 200 ) , value : dp [ i - 1 ] } } ,
133
+ { index : i - 2 , props : { x : 50 + ( i - 2 ) * 100 , y : 300 - Math . min ( ( i - 2 ) * 50 , 200 ) , value : dp [ i - 2 ] } }
134
+ ] ,
135
+ matrixUpdates : [ ] ,
136
+ formulaUpdate : `f(${ i } ) = f(${ i - 1 } ) + f(${ i - 2 } )`
137
+ } ,
138
+ interactionPoints : [ ]
139
+ } ) ;
140
+
141
+ // 添加到时间线 - 状态转移计算
80
142
timeline . push ( {
81
143
timestamp : stepCounter ++ * 1000 ,
82
- description : `计算第 ${ i } 阶的爬法数量 ` ,
144
+ description : `计算第${ i } 阶的爬法:从第 ${ i - 1 } 阶爬1阶的方法数( ${ dp [ i - 1 ] } )加上从第 ${ i - 2 } 阶爬2阶的方法数( ${ dp [ i - 2 ] } ) ` ,
83
145
visualChanges : {
84
146
nodeUpdates : [
85
147
{
@@ -98,21 +160,68 @@ export function generateDPSolution(n: number): {
98
160
} ) ;
99
161
}
100
162
101
- // 滚动数组优化阶段
163
+ // 结果展示
164
+ timeline . push ( {
165
+ timestamp : stepCounter ++ * 1000 ,
166
+ description : `得到结果:爬到第${ n } 阶总共有${ dp [ n ] } 种不同的方法` ,
167
+ visualChanges : {
168
+ nodeUpdates : [
169
+ { index : n , props : { x : 50 + n * 100 , y : 300 - Math . min ( n * 50 , 200 ) , value : dp [ n ] } }
170
+ ] ,
171
+ matrixUpdates : [ ] ,
172
+ formulaUpdate : `f(${ n } )=${ dp [ n ] } `
173
+ } ,
174
+ interactionPoints : [ ]
175
+ } ) ;
176
+
177
+ // 空间优化解释
178
+ timeline . push ( {
179
+ timestamp : stepCounter ++ * 1000 ,
180
+ description : "动态规划优化:我们只需要保存前两个状态,可以将空间复杂度从O(n)优化到O(1)" ,
181
+ visualChanges : {
182
+ nodeUpdates : [ ] ,
183
+ matrixUpdates : [ ] ,
184
+ formulaUpdate : "滚动数组:p=f(n-2), q=f(n-1), r=p+q"
185
+ } ,
186
+ interactionPoints : [ ]
187
+ } ) ;
188
+
189
+ // 空间优化过程
190
+ timeline . push ( {
191
+ timestamp : stepCounter ++ * 1000 ,
192
+ description : "使用三个变量p, q, r分别表示f(n-2), f(n-1), f(n),计算完一个状态后向前滚动" ,
193
+ visualChanges : {
194
+ nodeUpdates : [ ] ,
195
+ matrixUpdates : [ ] ,
196
+ formulaUpdate : "p←q, q←r, r=p+q"
197
+ } ,
198
+ interactionPoints : [ ]
199
+ } ) ;
200
+
201
+ // 时间复杂度分析
102
202
timeline . push ( {
103
203
timestamp : stepCounter ++ * 1000 ,
104
- description : "通过滚动数组,我们将空间复杂度从 O (n) 优化到 O (1)" ,
204
+ description : "算法分析:时间复杂度O (n),空间复杂度O (1),这是爬楼梯问题的最优解法 " ,
105
205
visualChanges : {
106
206
nodeUpdates : [ ] ,
107
207
matrixUpdates : [ ] ,
108
- formulaUpdate : "空间优化:只需保存前两个状态,p=f(n-2), q=f(n-1), r=p+q "
208
+ formulaUpdate : "时间O(n),空间O(1) "
109
209
} ,
110
210
interactionPoints : [ ]
111
211
} ) ;
112
212
113
213
return {
114
214
result : dp [ n ] ,
115
- timeline
215
+ timeline,
216
+ staircase : {
217
+ nodes : Array . from ( { length : n + 1 } , ( _ , i ) => ( {
218
+ id : i ,
219
+ x : 50 + i * 100 ,
220
+ y : 300 - Math . min ( i * 50 , 200 ) ,
221
+ value : dp [ i ]
222
+ } ) ) ,
223
+ links : links
224
+ }
116
225
} ;
117
226
}
118
227
0 commit comments