Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[pull] main from itcharge:main #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
pull merged 6 commits into AlgorithmAndLeetCode:main from itcharge:main
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
更新题解列表
  • Loading branch information
itcharge committed Apr 6, 2023
commit 10196df5fde9e7ed7429e9be9343bf9674ec71b9
69 changes: 57 additions & 12 deletions Solutions/0516. 最长回文子序列.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,70 @@

## 题目大意

给定一个字符串 `s`,找出其中最长的回文子序列,并返回该序列的长度。
**描述**:给定一个字符串 $s$。

**要求**:找出其中最长的回文子序列,并返回该序列的长度。

**说明**:

- **子序列**:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
- 1ドル \le s.length \le 1000$。
- $s$ 仅由小写英文字母组成。

**示例**:

- 示例 1:

```Python
输入:s = "bbbab"
输出:4
解释:一个可能的最长回文子序列为 "bbbb"。
```

- 示例 2:

```Python
输入:s = "cbbd"
输出:2
解释:一个可能的最长回文子序列为 "bb"。
```

## 解题思路

动态规划求解。
### 思路 1:动态规划

###### 1. 划分阶段

按照区间长度进行阶段划分。

###### 2. 定义状态

定义状态 `dp[i][j]` 表示为:字符串 `s` 在 `[i, j]` 范围内的最长回文子序列长度。
定义状态 $dp[i][j]$ 表示为:字符串 $s$ 在区间 $[i, j]$ 范围内的最长回文子序列长度。

则状态转移公式为:
###### 3. 状态转移方程

- 如果 `s[i] == s[j]`,则 `dp[i][j]` 为 `[i + 1, j - 1]` 范围内最长回文子序列长度 + 2,即 `dp[i][j] = dp[i + 1][j - 1] + 2`。
我们对区间 $[i, j]$ 边界位置上的字符 $s[i]$ 与 $s[j]$ 进行分类讨论:

- 如果 `s[i] != s[j]`,则 `dp[i][j]` 取决于以下两种情况,取其最大的一种:
1. 如果 $s[i] = s[j],ドル则 $dp[i][j]$ 为区间 $[i + 1, j - 1]$ 范围内最长回文子序列长度 + 2ドル,ドル即 $dp[i][j] = dp[i + 1][j - 1] + 2$。
2. 如果 $s[i] \ne s[j],ドル则 $dp[i][j]$ 取决于以下两种情况,取其最大的一种:
1. 加入 $s[i]$ 所能组成的最长回文子序列长度,即:$dp[i][j] = dp[i][j - 1]$。
2. 加入 $s[j]$ 所能组成的最长回文子序列长度,即:$dp[i][j] = dp[i - 1][j]$。

- 加入 `s[i]` 所能组成的最长回文子序列长度,即:`dp[i][j] = dp[i][j - 1]`。
- 加入 `s[j]` 所能组成的最长回文子序列长度,即:`dp[i][j] = dp[i - 1][j]`。
则状态转移方程为:

下一步确定遍历方向。
$dp[i][j] = \begin{cases} max \lbrace dp[i + 1][j - 1] + 2 \rbrace & s[i] = s[j] \cr max \lbrace dp[i][j - 1], dp[i - 1][j] \rbrace & s[i] \ne s[j] \end{cases}$

由于 `dp[i][j]` 依赖于 `dp[i + 1][j - 1]`、`dp[i + 1][j]`、`dp[i][j - 1]`,所以我们应该按照从下到上、从左到右的顺序进行遍历。
###### 4. 初始条件

最后输出 `[0, size - 1]` 范围内最长回文子序列长度,即 `dp[0][size - 1]` 为最终答案
- 单个字符的最长回文序列是 1ドル$,即 $dp[i][i] = 1$

## 代码
###### 5. 最终结果

由于 $dp[i][j]$ 依赖于 $dp[i + 1][j - 1]$、$dp[i + 1][j]$、$dp[i][j - 1],ドル所以我们应该按照从下到上、从左到右的顺序进行遍历。

根据我们之前定义的状态,$dp[i][j]$ 表示为:字符串 $s$ 在区间 $[i, j]$ 范围内的最长回文子序列长度。所以最终结果为 $dp[0][size - 1]$。

### 思路 1:代码

```Python
class Solution:
Expand All @@ -48,3 +88,8 @@ class Solution:
return dp[0][size - 1]
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(n^2),ドル其中 $n$ 为字符串 $s$ 的长度。
- **空间复杂度**:$O(n^2)$。

25 changes: 17 additions & 8 deletions Solutions/1547. 切棍子的最小成本.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -44,32 +44,39 @@
```Python
输入:n = 9, cuts = [5,6,1,4,2]
输出:22
解释:如果按给定的顺序切割,则总成本为 25。总成本 <= 25 的切割顺序很多,例如,[4, 6, 5, 2, 1] 的总成本 = 22,是所有可能方案中成本最小的。
解释:如果按给定的顺序切割,则总成本为 25。总成本 <= 25 的切割顺序很多,例如,[4, 6, 5, 2, 1] 的总成本 = 22,是所有可能方案中成本最小的。
```

## 解题思路

### 思路 1:动态规划

我们可以预先在数组 $cuts$ 种添加位置 0ドル$ 和位置 $n,ドル然后对数组 $cuts$ 进行排序。这样待切割的木棍就对应了数组中连续元素构成的「区间」。

###### 1. 划分阶段

按照 进行阶段划分
按照区间长度进行阶段划分

###### 2. 定义状态

定义状态 $dp[i]$ 表示为:。
定义状态 $dp[i][j]$ 表示为:切割区间为 $[i, j]$ 上的小木棍的最小成本

###### 3. 状态转移方程

假设位置 $i$ 与位置 $j$ 之间最后一个切割的位置为 $k,ドル则 $dp[i][j]$ 取决与由 $k$ 作为切割点分割出的两个区间 $[i, k]$ 与 $[k, j]$ 上的最小成本 + 切割位置 $k$ 所带来的成本。

而切割位置 $k$ 所带来的成本是这段区间所代表的小木棍的长度,即 $cuts[j] - cuts[i]$。

###### 4. 初始条件
则状态转移方程为:$dp[i][j] = min \lbrace dp[i][k] + dp[k][j] + cuts[j] - cuts[i] \rbrace, \quad i < k < j$

###### 4. 初始条件

- 相邻位置之间没有切割点,不需要切割,最小成本为 0ドル,ドル即 $dp[i - 1][i] = 0$。
- 其余位置默认为最小成本为一个极大值,即 $dp[i][j] = \infty, \quad i + 1 \ne j$。

###### 5. 最终结果

根据我们之前定义的状态,$dp[i]$ 表示为:。 所以最终结果为 $dp[size]$。
根据我们之前定义的状态,$dp[i][j]$ 表示为:切割区间为 $[i, j]$ 上的小木棍的最小成本。 所以最终结果为 $dp[0][size - 1]$。

### 思路 1:代码

Expand All @@ -81,7 +88,9 @@ class Solution:
cuts.sort()

size = len(cuts)
dp = [[0 for _ in range(size)] for _ in range(size)]
dp = [[float('inf') for _ in range(size)] for _ in range(size)]
for i in range(1, size):
dp[i - 1][i] = 0

for l in range(3, size + 1): # 枚举区间长度
for i in range(size): # 枚举区间起点
Expand All @@ -97,5 +106,5 @@ class Solution:

### 思路 1:复杂度分析

- **时间复杂度**:$O()$
- **空间复杂度**:
- **时间复杂度**:$O(m^3),ドル其中 $m$ 为数组 $cuts$ 的元素个数。
- **空间复杂度**:$O(m^2)$。

AltStyle によって変換されたページ (->オリジナル) /