Skip to content

Commit c34bf68

Browse files
committed
分割回文字符串
1 parent 3dbc197 commit c34bf68

File tree

1 file changed

+44
-81
lines changed

1 file changed

+44
-81
lines changed

basic_algorithm/dp.md

Lines changed: 44 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -283,97 +283,60 @@ bool canJump(vector<int>& nums) {
283283
> 数组中的每个元素代表你在该位置可以跳跃的最大长度。
284284
> 你的目标是使用最少的跳跃次数到达数组的最后一个位置。
285285
286-
```go
287-
// v1动态规划(其他语言超时参考v2)
288-
func jump(nums []int) int {
289-
// 状态:f[i] 表示从起点到当前位置最小次数
290-
// 推导:f[i] = f[j],a[j]+j >=i,min(f[j]+1)
291-
// 初始化:f[0] = 0
292-
// 结果:f[n-1]
293-
f := make([]int, len(nums))
294-
f[0] = 0
295-
for i := 1; i < len(nums); i++ {
296-
// f[i] 最大值为i
297-
f[i] = i
298-
// 遍历之前结果取一个最小值+1
299-
for j := 0; j < i; j++ {
300-
if nums[j]+j >= i {
301-
f[i] = min(f[j]+1,f[i])
302-
}
303-
}
304-
}
305-
return f[len(nums)-1]
306-
}
307-
func min(a, b int) int {
308-
if a > b {
309-
return b
310-
}
311-
return a
312-
}
313-
```
314-
315-
```go
316-
// v2 动态规划+贪心优化
317-
func jump(nums []int) int {
318-
n:=len(nums)
319-
f := make([]int, n)
320-
f[0] = 0
321-
for i := 1; i < n; i++ {
322-
// 取第一个能跳到当前位置的点即可
323-
// 因为跳跃次数的结果集是单调递增的,所以贪心思路是正确的
324-
idx:=0
325-
for idx<n&&idx+nums[idx]<i{
326-
idx++
286+
```c++
287+
int jump(vector<int>& nums) {
288+
int size = nums.size();
289+
vector<int> cache(size);
290+
cache[0] = 0;
291+
// cache[i + 1] >= cache[i]
292+
for (int i = 1, farest = 0; i < size; ++i) {
293+
while (farest < size && farest + nums[farest] < i) {
294+
++farest;
327295
}
328-
f[i]=f[idx]+1
296+
// 假设你总是可以到达数组的最后一个位置。
297+
// 可以认定farest + nums[farest]一定会大于i
298+
cache[i] = cache[farest] + 1;
329299
}
330-
return f[n-1]
300+
return cache.back();
331301
}
332-
333302
```
334303
335304
### [palindrome-partitioning-ii](https://leetcode-cn.com/problems/palindrome-partitioning-ii/)
336305
337306
> 给定一个字符串 _s_,将 _s_ 分割成一些子串,使每个子串都是回文串。
338307
> 返回符合要求的最少分割次数。
339308
340-
```go
341-
func minCut(s string) int {
342-
// state: f[i] "前i"个字符组成的子字符串需要最少几次cut(个数-1为索引)
343-
// function: f[i] = MIN{f[j]+1}, j < i && [j+1 ~ i]这一段是一个回文串
344-
// intialize: f[i] = i - 1 (f[0] = -1)
345-
// answer: f[s.length()]
346-
if len(s) == 0 || len(s) == 1 {
347-
return 0
348-
}
349-
f := make([]int, len(s)+1)
350-
f[0] = -1
351-
f[1] = 0
352-
for i := 1; i <= len(s); i++ {
353-
f[i] = i - 1
354-
for j := 0; j < i; j++ {
355-
if isPalindrome(s, j, i-1) {
356-
f[i] = min(f[i], f[j]+1)
357-
}
358-
}
359-
}
360-
return f[len(s)]
361-
}
362-
func min(a, b int) int {
363-
if a > b {
364-
return b
365-
}
366-
return a
367-
}
368-
func isPalindrome(s string, i, j int) bool {
369-
for i < j {
370-
if s[i] != s[j] {
371-
return false
372-
}
373-
i++
374-
j--
375-
}
376-
return true
309+
```c++
310+
int minCut(string s) {
311+
if (s.size() <= 1) {
312+
return 0;
313+
}
314+
auto size = s.size();
315+
vector<int> cache(size);
316+
for (int i = 0; i < size; ++i) {
317+
cache[i] = i;
318+
}
319+
vector<vector<bool>> isPalindrome(size, vector<bool>(size));
320+
for (int right = 0; right < size; ++right) {
321+
for (int left = 0; left <= right; ++left) {
322+
// 如果头尾相同,可能为回文!
323+
// len < 3时,直接判断为回文
324+
// len >= 3时,判断里面一层,左右往里缩一格
325+
isPalindrome[left][right] = s[right] == s[left] && (right - left < 3 || isPalindrome[left + 1][right - 1]);
326+
}
327+
}
328+
for (int i = 1; i < size; ++i) {
329+
if (isPalindrome[0][i]) {
330+
cache[i] = 0;
331+
continue;
332+
}
333+
for (int j = 0; j < i; ++j) {
334+
if (isPalindrome[j + 1][i]) {
335+
cache[i] = min(cache[j] + 1, cache[i]);
336+
}
337+
}
338+
}
339+
return cache.back();
377340
}
378341
```
379342

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy