88
88
89
89
<!-- solution:start -->
90
90
91
- ### 方法一:记忆化搜索
91
+ ### 方法一:前缀和 + 记忆化搜索
92
+
93
+ 我们用一个数组 $\textit{nums}$ 记录每个单词的长度,数组的长度记为 $n$。然后我们定义一个长度为 $n + 1$ 的前缀和数组 $\textit{s}$,其中 $\textit{s}[ i] $ 表示前 $i$ 个单词的长度之和。
94
+
95
+ 接下来,我们设计一个函数 $\textit{dfs}(i)$,表示从第 $i$ 个单词开始分隔句子的最小成本。那么答案为 $\textit{dfs}(0)$。
96
+
97
+ 函数 $\textit{dfs}(i)$ 的执行过程如下:
98
+
99
+ - 如果从第 $i$ 个单词开始到最后一个单词的长度之和加上单词之间的空格数小于等于 $k$,那么这些单词可以放在最后一行,成本为 $0$。
100
+ - 否则,我们枚举下一个开始分隔的单词的位置 $j$,使得从第 $i$ 个单词到第 $j-1$ 个单词的长度之和加上单词之间的空格数小于等于 $k$。那么 $\textit{dfs}(j)$ 表示从第 $j$ 个单词开始分隔句子的最小成本,而 $(k - m)^2$ 表示将第 $i$ 个单词到第 $j-1$ 个单词放在一行的成本,其中 $m$ 表示从第 $i$ 个单词到第 $j-1$ 个单词的长度之和加上单词之间的空格数。我们枚举所有的 $j$,取最小值即可。
101
+
102
+ 答案即为 $\textit{dfs}(0)$。
103
+
104
+ 为了避免重复计算,我们可以使用记忆化搜索。
105
+
106
+ 时间复杂度 $O(n^2)$,空间复杂度 $O(n)$。其中 $n$ 为单词的个数。
92
107
93
108
<!-- tabs:start -->
94
109
@@ -98,59 +113,56 @@ tags:
98
113
class Solution :
99
114
def minimumCost (self , sentence : str , k : int ) -> int :
100
115
@cache
101
- def dfs (i ) :
102
- if s[- 1 ] - s[i] + n - i - 1 <= k:
116
+ def dfs (i : int ) -> int :
117
+ if s[n ] - s[i] + n - i - 1 <= k:
103
118
return 0
104
- ans, j = inf, i + 1
105
- while j < n and (t := s[j] - s[i] + j - i - 1 ) <= k:
106
- ans = min (ans, (k - t) ** 2 + dfs(j))
119
+ ans = inf
120
+ j = i + 1
121
+ while j < n and (m := s[j] - s[i] + j - i - 1 ) <= k:
122
+ ans = min (ans, dfs(j) + (k - m) ** 2 )
107
123
j += 1
108
124
return ans
109
125
110
- t = [len (w ) for w in sentence.split()]
111
- n = len (t )
112
- s = list (accumulate(t , initial = 0 ))
126
+ nums = [len (s ) for s in sentence.split()]
127
+ n = len (nums )
128
+ s = list (accumulate(nums , initial = 0 ))
113
129
return dfs(0 )
114
130
```
115
131
116
132
#### Java
117
133
118
134
``` java
119
135
class Solution {
120
- private static final int INF = Integer . MAX_VALUE ;
121
- private int [] memo;
136
+ private Integer [] f;
122
137
private int [] s;
138
+ private int k;
123
139
private int n;
124
140
125
141
public int minimumCost (String sentence , int k ) {
142
+ this . k = k;
126
143
String [] words = sentence. split(" " );
127
144
n = words. length;
145
+ f = new Integer [n];
128
146
s = new int [n + 1 ];
129
147
for (int i = 0 ; i < n; ++ i) {
130
148
s[i + 1 ] = s[i] + words[i]. length();
131
149
}
132
- memo = new int [n];
133
- Arrays . fill(memo, INF );
134
- return dfs(0 , k);
150
+ return dfs(0 );
135
151
}
136
152
137
- private int dfs (int i , int k ) {
138
- if (memo[i] != INF ) {
139
- return memo[i];
140
- }
153
+ private int dfs (int i ) {
141
154
if (s[n] - s[i] + n - i - 1 <= k) {
142
- memo[i] = 0 ;
143
155
return 0 ;
144
156
}
145
- int ans = INF ;
146
- for (int j = i + 1 ; j < n; ++ j) {
147
- int t = s[j] - s[i] + j - i - 1 ;
148
- if (t <= k) {
149
- ans = Math . min(ans, (k - t) * (k - t) + dfs(j, k));
150
- }
157
+ if (f[i] != null ) {
158
+ return f[i];
159
+ }
160
+ int ans = Integer . MAX_VALUE ;
161
+ for (int j = i + 1 ; j < n && s[j] - s[i] + j - i - 1 <= k; ++ j) {
162
+ int m = s[j] - s[i] + j - i - 1 ;
163
+ ans = Math . min(ans, dfs(j) + (k - m) * (k - m));
151
164
}
152
- memo[i] = ans;
153
- return ans;
165
+ return f[i] = ans;
154
166
}
155
167
}
156
168
```
@@ -160,34 +172,31 @@ class Solution {
160
172
``` cpp
161
173
class Solution {
162
174
public:
163
- const int inf = INT_MAX;
164
- int n;
165
-
166
175
int minimumCost(string sentence, int k) {
167
- istringstream is(sentence);
168
- vector<string> words;
169
- string word;
170
- while (is >> word) words.push_back(word);
171
- n = words.size();
172
- vector<int> s(n + 1);
173
- for (int i = 0; i < n; ++i) s[i + 1] = s[i] + words[i].size();
174
- vector<int> memo(n, inf);
175
- return dfs(0, k, s, memo);
176
- }
177
-
178
- int dfs (int i, int k, vector<int >& s, vector<int >& memo) {
179
- if (memo[ i] != inf) return memo[ i] ;
180
- if (s[ n] - s[ i] + n - i - 1 <= k) {
181
- memo[ i] = 0;
182
- return 0;
183
- }
184
- int ans = inf;
185
- for (int j = i + 1; j < n; ++j) {
186
- int t = s[ j] - s[ i] + j - i - 1;
187
- if (t <= k) ans = min(ans, (k - t) * (k - t) + dfs(j, k, s, memo));
176
+ istringstream iss(sentence);
177
+ vector<int > s = {0};
178
+ string w;
179
+ while (iss >> w) {
180
+ s.push_back(s.back() + w.size());
188
181
}
189
- memo[ i] = ans;
190
- return ans;
182
+ int n = s.size() - 1;
183
+ int f[ n] ;
184
+ memset(f, -1, sizeof(f));
185
+ auto dfs = [ &] (auto&& dfs, int i) -> int {
186
+ if (s[ n] - s[ i] + n - i - 1 <= k) {
187
+ return 0;
188
+ }
189
+ if (f[ i] != -1) {
190
+ return f[ i] ;
191
+ }
192
+ int ans = INT_MAX;
193
+ for (int j = i + 1; j < n && s[ j] - s[ i] + j - i - 1 <= k; ++j) {
194
+ int m = s[ j] - s[ i] + j - i - 1;
195
+ ans = min(ans, dfs(dfs, j) + (k - m) * (k - m));
196
+ }
197
+ return f[ i] = ans;
198
+ };
199
+ return dfs(dfs, 0);
191
200
}
192
201
};
193
202
```
@@ -196,40 +205,63 @@ public:
196
205
197
206
```go
198
207
func minimumCost(sentence string, k int) int {
199
- words := strings.Split(sentence, " ")
200
- n := len(words)
201
- inf := math.MaxInt32
202
- s := make([]int, n+1)
203
- for i, word := range words {
204
- s[i+1] = s[i] + len(word)
208
+ s := []int{0}
209
+ for _, w := range strings.Split(sentence, " ") {
210
+ s = append(s, s[len(s)-1]+len(w))
205
211
}
206
- memo := make([]int, n)
207
- for i := range memo {
208
- memo[i] = inf
212
+ n := len(s) - 1
213
+ f := make([]int, n)
214
+ for i := range f {
215
+ f[i] = -1
209
216
}
210
217
var dfs func(int) int
211
218
dfs = func(i int) int {
212
- if memo[i] != inf {
213
- return memo[i]
214
- }
215
219
if s[n]-s[i]+n-i-1 <= k {
216
- memo[i] = 0
217
220
return 0
218
221
}
219
- ans := inf
220
- for j := i + 1; j < n; j++ {
221
- t := s[j] - s[i] + j - i - 1
222
- if t <= k {
223
- ans = min(ans, (k-t)*(k-t)+dfs(j))
224
- }
222
+ if f[i] != -1 {
223
+ return f[i]
225
224
}
226
- memo[i] = ans
225
+ ans := math.MaxInt32
226
+ for j := i + 1; j < n && s[j]-s[i]+j-i-1 <= k; j++ {
227
+ m := s[j] - s[i] + j - i - 1
228
+ ans = min(ans, dfs(j)+(k-m)*(k-m))
229
+ }
230
+ f[i] = ans
227
231
return ans
228
232
}
229
233
return dfs(0)
230
234
}
231
235
```
232
236
237
+ #### TypeScript
238
+
239
+ ``` ts
240
+ function minimumCost(sentence : string , k : number ): number {
241
+ const s: number [] = [0 ];
242
+ for (const w of sentence .split (' ' )) {
243
+ s .push (s .at (- 1 )! + w .length );
244
+ }
245
+ const n = s .length - 1 ;
246
+ const f: number [] = Array (n ).fill (- 1 );
247
+ const dfs = (i : number ): number => {
248
+ if (s [n ] - s [i ] + n - i - 1 <= k ) {
249
+ return 0 ;
250
+ }
251
+ if (f [i ] !== - 1 ) {
252
+ return f [i ];
253
+ }
254
+ let ans = Infinity ;
255
+ for (let j = i + 1 ; j < n && s [j ] - s [i ] + j - i - 1 <= k ; ++ j ) {
256
+ const m = s [j ] - s [i ] + j - i - 1 ;
257
+ ans = Math .min (ans , dfs (j ) + (k - m ) ** 2 );
258
+ }
259
+ return (f [i ] = ans );
260
+ };
261
+ return dfs (0 );
262
+ }
263
+ ```
264
+
233
265
<!-- tabs: end -->
234
266
235
267
<!-- solution: end -->
0 commit comments