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
andj
, and flip boths1[i]
ands1[j]
. The cost of this operation isx
. - Choose an index
i
such thati < n - 1
and flip boths1[i]
ands1[i + 1]
. The cost of this operation is1
.
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
ands2
consist only of the characters'0'
and'1'
.
We notice that since each operation reverses two characters, if the number of different characters in the two strings is odd, it is impossible to make them equal, and we directly return
Next, we design a function
The calculation process of the function
If
Otherwise, we consider the two endpoints of the interval
- If we perform the first operation on endpoint
, since the cost is fixed, the optimal choice is to reverse and , and then recursively calculate , with a total cost of . - If we perform the second operation on endpoint
, we need to reverse all the characters in , and then recursively calculate , with a total cost of . - If we perform the second operation on endpoint
, we need to reverse all the characters in , and then recursively calculate , with a total cost of .
We take the minimum value of the above three operations as the value of
To avoid redundant calculations, we can use memoization to record the return value of
The time complexity is
class Solution:
def minOperations(self, s1: str, s2: str, x: int) -> int:
@cache
def dfs(i: int, j: int) -> int:
if i > j:
return 0
a = dfs(i + 1, j - 1) + x
b = dfs(i + 2, j) + idx[i + 1] - idx[i]
c = dfs(i, j - 2) + idx[j] - idx[j - 1]
return min(a, b, c)
n = len(s1)
idx = [i for i in range(n) if s1[i] != s2[i]]
m = len(idx)
if m & 1:
return -1
return dfs(0, m - 1)
class Solution {
private List<Integer> idx = new ArrayList<>();
private Integer[][] f;
private int x;
public int minOperations(String s1, String s2, int x) {
int n = s1.length();
for (int i = 0; i < n; ++i) {
if (s1.charAt(i) != s2.charAt(i)) {
idx.add(i);
}
}
int m = idx.size();
if (m % 2 == 1) {
return -1;
}
this.x = x;
f = new Integer[m][m];
return dfs(0, m - 1);
}
private int dfs(int i, int j) {
if (i > j) {
return 0;
}
if (f[i][j] != null) {
return f[i][j];
}
f[i][j] = dfs(i + 1, j - 1) + x;
f[i][j] = Math.min(f[i][j], dfs(i + 2, j) + idx.get(i + 1) - idx.get(i));
f[i][j] = Math.min(f[i][j], dfs(i, j - 2) + idx.get(j) - idx.get(j - 1));
return f[i][j];
}
}
class Solution {
public:
int minOperations(string s1, string s2, int x) {
vector<int> idx;
for (int i = 0; i < s1.size(); ++i) {
if (s1[i] != s2[i]) {
idx.push_back(i);
}
}
int m = idx.size();
if (m & 1) {
return -1;
}
if (m == 0) {
return 0;
}
int f[m][m];
memset(f, -1, sizeof(f));
function<int(int, int)> dfs = [&](int i, int j) {
if (i > j) {
return 0;
}
if (f[i][j] != -1) {
return f[i][j];
}
f[i][j] = min({dfs(i + 1, j - 1) + x, dfs(i + 2, j) + idx[i + 1] - idx[i], dfs(i, j - 2) + idx[j] - idx[j - 1]});
return f[i][j];
};
return dfs(0, m - 1);
}
};
func minOperations(s1 string, s2 string, x int) int {
idx := []int{}
for i := range s1 {
if s1[i] != s2[i] {
idx = append(idx, i)
}
}
m := len(idx)
if m&1 == 1 {
return -1
}
f := make([][]int, m)
for i := range f {
f[i] = make([]int, m)
for j := range f[i] {
f[i][j] = -1
}
}
var dfs func(i, j int) int
dfs = func(i, j int) int {
if i > j {
return 0
}
if f[i][j] != -1 {
return f[i][j]
}
f[i][j] = dfs(i+1, j-1) + x
f[i][j] = min(f[i][j], dfs(i+2, j)+idx[i+1]-idx[i])
f[i][j] = min(f[i][j], dfs(i, j-2)+idx[j]-idx[j-1])
return f[i][j]
}
return dfs(0, m-1)
}
function minOperations(s1: string, s2: string, x: number): number {
const idx: number[] = [];
for (let i = 0; i < s1.length; ++i) {
if (s1[i] !== s2[i]) {
idx.push(i);
}
}
const m = idx.length;
if (m % 2 === 1) {
return -1;
}
if (m === 0) {
return 0;
}
const f: number[][] = Array.from({ length: m }, () => Array.from({ length: m }, () => -1));
const dfs = (i: number, j: number): number => {
if (i > j) {
return 0;
}
if (f[i][j] !== -1) {
return f[i][j];
}
f[i][j] = dfs(i + 1, j - 1) + x;
f[i][j] = Math.min(f[i][j], dfs(i + 2, j) + idx[i + 1] - idx[i]);
f[i][j] = Math.min(f[i][j], dfs(i, j - 2) + idx[j] - idx[j - 1]);
return f[i][j];
};
return dfs(0, m - 1);
}
class Solution {
public int minOperations(String s1, String s2, int x) {
int n = s1.length();
int inf = 50_000;
int one = inf, two = inf, last = inf;
int done = 0;
for (int i = 0; i < n; i++) {
if (s1.charAt(i) == s2.charAt(i)) {
one = Math.min(one, last);
last = last + 1;
two = two + 1;
continue;
}
if (done < n) {
one = Math.min(two + 1, done + x);
last = Math.min(two + x, done);
done = two = inf;
continue;
}
done = Math.min(one + x, last + 1);
two = one;
one = last = inf;
continue;
}
return done == inf ? -1 : done;
}
}