Skip to content

feat: add solutions to lc problem: No.3579 #4482

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
merged 2 commits into from
Jun 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,17 @@ tags:

<!-- solution:start -->

### 方法一
### 方法一:贪心 + 动态规划

我们定义 $f[i]$ 表示将 $\textit{word1}$ 的前 $i$ 个字符转换为 $\textit{word2}$ 的前 $i$ 个字符所需的最小操作数。那么答案为 $f[n]$,其中 $n$ 是 $\textit{word1}$ 和 $\textit{word2}$ 的长度。

我们可以通过遍历所有可能的分割点来计算 $f[i]$。对于每个分割点 $j$,我们需要计算将 $\textit{word1}[j:i]$ 转换为 $\textit{word2}[j:i]$ 所需的最小操作数。

我们可以使用一个辅助函数 $\text{calc}(l, r, \text{rev})$ 来计算从 $\textit{word1}[l:r]$ 转换为 $\textit{word2}[l:r]$ 所需的最小操作数,其中 $\text{rev}$ 表示是否需要反转子串。由于反转前后进行其它操作的结果是一样的,所以我们可以考虑不反转,以及首先进行一次反转后再进行其它操作。因此有 $f[i] = \min_{j < i} (f[j] + \min(\text{calc}(j, i-1, \text{false}), 1 + \text{calc}(j, i-1, \text{true})))$。

接下来我们需要实现 $\text{calc}(l, r, \text{rev})$ 函数。我们用一个二维数组 $cnt$ 来记录 $\textit{word1}$ 和 $\textit{word2}$ 中字符的配对情况。对于每个字符对 $(a, b)$,如果 $a \neq b$,我们需要检查 $cnt[b][a]$ 是否大于 $0$。如果是,我们可以将其配对,减少一次操作;否则,我们需要增加一次操作,并将 $cnt[a][b]$ 加 $1$。

时间复杂度 $O(n^3 + |\Sigma|^2)$,空间复杂度 $O(n + |\Sigma|^2)$,其中 $n$ 是字符串的长度,而 $|\Sigma|$ 是字符集大小(本题中为 $26$)。

<!-- tabs:start -->

Expand Down Expand Up @@ -357,6 +367,53 @@ function minOperations(word1: string, word2: string): number {
}
```

#### Rust

```rust
impl Solution {
pub fn min_operations(word1: String, word2: String) -> i32 {
let n = word1.len();
let word1 = word1.as_bytes();
let word2 = word2.as_bytes();
let mut f = vec![i32::MAX; n + 1];
f[0] = 0;

for i in 1..=n {
for j in 0..i {
let a = Self::calc(word1, word2, j, i - 1, false);
let b = 1 + Self::calc(word1, word2, j, i - 1, true);
let t = a.min(b);
f[i] = f[i].min(f[j] + t);
}
}

f[n]
}

fn calc(word1: &[u8], word2: &[u8], l: usize, r: usize, rev: bool) -> i32 {
let mut cnt = [[0i32; 26]; 26];
let mut res = 0;

for i in l..=r {
let j = if rev { r - (i - l) } else { i };
let a = (word1[j] - b'a') as usize;
let b = (word2[i] - b'a') as usize;

if a != b {
if cnt[b][a] > 0 {
cnt[b][a] -= 1;
} else {
cnt[a][b] += 1;
res += 1;
}
}
}

res
}
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,17 @@ tags:

<!-- solution:start -->

### Solution 1
### Solution 1: Greedy + Dynamic Programming

We define $f[i]$ as the minimum number of operations required to convert the first $i$ characters of $\textit{word1}$ to the first $i$ characters of $\textit{word2}$. The answer is $f[n]$, where $n$ is the length of both $\textit{word1}$ and $\textit{word2}$.

We can compute $f[i]$ by enumerating all possible split points. For each split point $j$, we need to calculate the minimum number of operations required to convert $\textit{word1}[j:i]$ to $\textit{word2}[j:i]$.

We can use a helper function $\text{calc}(l, r, \text{rev})$ to compute the minimum number of operations needed to convert $\textit{word1}[l:r]$ to $\textit{word2}[l:r]$, where $\text{rev}$ indicates whether to reverse the substring. Since the result of performing other operations before or after a reversal is the same, we only need to consider not reversing, and reversing once before other operations. Therefore, $f[i] = \min_{j < i} (f[j] + \min(\text{calc}(j, i-1, \text{false}), 1 + \text{calc}(j, i-1, \text{true})))$.

Next, we need to implement the $\text{calc}(l, r, \text{rev})$ function. We use a 2D array $cnt$ to record the pairing status of characters between $\textit{word1}$ and $\textit{word2}$. For each character pair $(a, b)$, if $a \neq b$, we check whether $cnt[b][a] > 0$. If so, we can pair them and reduce one operation; otherwise, we need to add one operation and increment $cnt[a][b]$ by $1$.

The time complexity is $O(n^3 + |\Sigma|^2)$ and the space complexity is $O(n + |\Sigma|^2)$, where $n$ is the length of the string and $|\Sigma|$ is the size of the character set (which is $26$ in this problem).

<!-- tabs:start -->

Expand Down Expand Up @@ -352,6 +362,53 @@ function minOperations(word1: string, word2: string): number {
}
```

#### Rust

```rust
impl Solution {
pub fn min_operations(word1: String, word2: String) -> i32 {
let n = word1.len();
let word1 = word1.as_bytes();
let word2 = word2.as_bytes();
let mut f = vec![i32::MAX; n + 1];
f[0] = 0;

for i in 1..=n {
for j in 0..i {
let a = Self::calc(word1, word2, j, i - 1, false);
let b = 1 + Self::calc(word1, word2, j, i - 1, true);
let t = a.min(b);
f[i] = f[i].min(f[j] + t);
}
}

f[n]
}

fn calc(word1: &[u8], word2: &[u8], l: usize, r: usize, rev: bool) -> i32 {
let mut cnt = [[0i32; 26]; 26];
let mut res = 0;

for i in l..=r {
let j = if rev { r - (i - l) } else { i };
let a = (word1[j] - b'a') as usize;
let b = (word2[i] - b'a') as usize;

if a != b {
if cnt[b][a] > 0 {
cnt[b][a] -= 1;
} else {
cnt[a][b] += 1;
res += 1;
}
}
}

res
}
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
impl Solution {
pub fn min_operations(word1: String, word2: String) -> i32 {
let n = word1.len();
let word1 = word1.as_bytes();
let word2 = word2.as_bytes();
let mut f = vec![i32::MAX; n + 1];
f[0] = 0;

for i in 1..=n {
for j in 0..i {
let a = Self::calc(word1, word2, j, i - 1, false);
let b = 1 + Self::calc(word1, word2, j, i - 1, true);
let t = a.min(b);
f[i] = f[i].min(f[j] + t);
}
}

f[n]
}

fn calc(word1: &[u8], word2: &[u8], l: usize, r: usize, rev: bool) -> i32 {
let mut cnt = [[0i32; 26]; 26];
let mut res = 0;

for i in l..=r {
let j = if rev { r - (i - l) } else { i };
let a = (word1[j] - b'a') as usize;
let b = (word2[i] - b'a') as usize;

if a != b {
if cnt[b][a] > 0 {
cnt[b][a] -= 1;
} else {
cnt[a][b] += 1;
res += 1;
}
}
}

res
}
}