leetcode
leetcode 2701 ~ 2750
执行操作使两个字符串相等

执行操作使两个字符串相等

难度:

标签:

题目描述

You are given two 0-indexed binary strings s1 and s2, both of length n, and a positive integer x.

You can perform any of the following operations on the string s1 any number of times:

  • Choose two indices i and j, and flip both s1[i] and s1[j]. The cost of this operation is x.
  • Choose an index i such that i < n - 1 and flip both s1[i] and s1[i + 1]. The cost of this operation is 1.

Return the minimum cost needed to make the strings s1 and s2 equal, or return -1 if it is impossible.

Note that flipping a character means changing it from 0 to 1 or vice-versa.

 

Example 1:

Input: s1 = "1100011000", s2 = "0101001010", x = 2
Output: 4
Explanation: We can do the following operations:
- Choose i = 3 and apply the second operation. The resulting string is s1 = "1101111000".
- Choose i = 4 and apply the second operation. The resulting string is s1 = "1101001000".
- Choose i = 0 and j = 8 and apply the first operation. The resulting string is s1 = "0101001010" = s2.
The total cost is 1 + 1 + 2 = 4. It can be shown that it is the minimum cost possible.

Example 2:

Input: s1 = "10110", s2 = "00011", x = 4
Output: -1
Explanation: It is not possible to make the two strings equal.

 

Constraints:

  • n == s1.length == s2.length
  • 1 <= n, x <= 500
  • s1 and s2 consist only of the characters '0' and '1'.

代码结果

运行时间: 30 ms, 内存: 16.1 MB


/*
 * 题目思路:
 * 我们需要通过反转操作使s1和s2相等。
 * 1. 首先,我们记录所有不同的位置的下标。
 * 2. 然后,优先使用第二种操作将相邻的不同位置反转,代价为1。
 * 3. 对于不相邻的不同位置,如果x的代价小于两次第二种操作的代价,我们选择第一种操作,代价为x。
 * 4. 最终计算最小代价,如果不能使两者相等,返回-1。
 */
import java.util.stream.IntStream;

public class Solution {
    public int minCost(String s1, String s2, int x) {
        int n = s1.length();
        int[] diffIndices = IntStream.range(0, n)
                                     .filter(i -> s1.charAt(i) != s2.charAt(i))
                                     .toArray();
        int diffCount = diffIndices.length;

        if (diffCount == 0) return 0; // 已经相等
        if (diffCount % 2 != 0) return -1; // 奇数个不同,无法使其相等

        int cost = 0;
        int i = 0;

        // 处理相邻的不同位置
        while (i < diffCount - 1) {
            if (diffIndices[i + 1] == diffIndices[i] + 1) {
                cost += 1;
                i += 2;
            } else {
                i += 1;
            }
        }

        // 处理不相邻的不同位置
        for (int j = i; j < diffCount; j += 2) {
            cost += Math.min(2, x);
        }

        return cost;
    }
}

解释

方法:

题解通过首先比较两个字符串s1和s2的每个对应字符,找出所有不同的位置。然后检查不同位置的个数,如果是奇数,则返回-1,因为每次操作至少修改两个字符。对于偶数个不同位置,题解采用动态规划的方法,用a和b来存储当前和下一步的最小代价。对于每一对不同位置,计算通过直接交换这两个位置的字符或者通过一系列操作让这两个位置的字符相同的最小代价,更新a和b的值。最后返回代价b除以2的值。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在不同字符数量为奇数时直接返回-1?这意味着什么样的情况下无法通过任何操作使得s1和s2相等?
当不同字符的数量为奇数时,意味着至少有一个字符无法找到另一个不同的字符与之配对进行交换或变更操作。每次操作至少涉及两个字符的修改,如果剩下一个单独的不同字符,就没有办法通过一次操作解决这个不匹配,因此无法通过任何操作使两个字符串完全相等。
🦆
在对每对索引计算最小代价时,表达式`b + x`和`a + (j - i) * 2`分别代表什么含义?为什么选择这两种方式计算代价?
在这个题解中,`b + x`代表使用之前的最小代价(b)并加上一次新的操作成本(x),这表示跳过一个当前不匹配的位置并处理下一个。而`a + (j - i) * 2`代表使用上一个不匹配(a)的代价,并加上当前位置到下一个不匹配位置的距离乘以2,这代表解决当前的不匹配(通过修改两个字符的方式)。选择这两种方式是为了确保能找到在当前步骤中可能的最小操作成本,从而整体上达到最小化修改字符串的总代价。
🦆
对于`pairwise(idxs)`函数的使用,这个函数是如何工作的,它如何帮助在题解中处理索引对?
`pairwise`函数用于生成一个迭代器,这个迭代器会返回原始列表中每对相邻元素的元组,例如,列表[1, 2, 3, 4]会被`pairwise`处理成[(1, 2), (2, 3), (3, 4)]。在本题解中,使用`pairwise(idxs)`帮助处理每一对不同字符的索引,这是因为每次操作都会考虑两个不同位置的字符,从而计算这两个位置间的最小代价。这样可以直接在两个不同字符之间建立关联,计算出最优解。

相关问题