给定一个二进制字符串S。求将数字0转换为 S 表示的数字所需的最少操作次数。
允许执行两种类型的操作:
- 添加2个
- 减去2 x
注意:从 0 开始执行操作。
例子:
Input : 100
Output : 1
Explanation: We just perform a single operation, i.e Add 4 (2^2)
Input : 111
Output : 2
Explanation: We perform the following two operations:
1) Add 8(2^3)
2) Subtract 1(2^0)
这个想法是使用动态规划来解决这个问题。
注意:在下面的分析中,我们认为所有的二进制字符串都是从 LSB 到 MSB(从 LHS 到 RHS)表示的,即 2(二进制形式:“10”)表示为“01”。
令给定的二进制字符串为 S。
令dp[i][0]表示生成二进制字符串R 所需的最小运算次数,使得 R[0…i] 与 S[0…i] 相同且 R[i+1…] = “00 ..0”
类似地,让dp[i][1]表示生成二进制字符串R 所需的最小运算次数,使得 R[0…i] 与 S[0…i] 相同且 R[i+1…] = “11..1”
如果 S i为“0”,则 dp[i][0] = dp[i – 1][0]。因为我们不需要任何额外的操作。现在我们考虑 dp[i][1] 的值,这有点棘手。对于 dp[i][1],我们可以通过使 dp[i-1][1], ‘0’ 形成的字符串的第i个字符从 dp[i – 1][1] 进行转换.从以前开始,第 i个字符是“1”。我们只需要从 dp[i-1][0] 表示的字符串减去 2 i 。因此,我们执行除 dp[i-1][0] 表示的操作之外的一项操作。
另一个转换可能来自 dp[i-1][0]。让 dp[i-1][1] 代表字符串R。然后我们需要保持 R[i] = 0,因为它已经是,但是 R[i + 1…..] 当前是“000..0”,需要更改为“111…1”,这可以通过从 R 中减去 2 (i+1)来完成。因此我们只需要除 dp[i-1][0] 表示的操作之外的一个操作。
当S i为’1’时情况类似。
最终的答案是 dp[l-1][0] 表示的那个,其中 l 是二进制字符串S 的长度。
下面是上述方法的实现:
C++
// CPP program to find the minimum number
// of operations required to sum to N
#include
using namespace std;
// Function to return the minimum operations required
// to sum to a number reprented by the binary string S
int findMinOperations(string S)
{
// Reverse the string to consider
// it from LSB to MSB
reverse(S.begin(), S.end());
int n = S.length();
// initialise the dp table
int dp[n + 1][2];
// If S[0] = '0', there is no need to
// perform any operation
if (S[0] == '0') {
dp[0][0] = 0;
}
else {
// If S[0] = '1', just perform a single
// operation(i.e Add 2^0)
dp[0][0] = 1;
}
// Irrespective of the LSB, dp[0][1] is always
// 1 as there is always the need of making the
// suffix of the binary string of the form "11....1"
// as suggested by the definition of dp[i][1]
dp[0][1] = 1;
for (int i = 1; i < n; i++) {
if (S[i] == '0') {
// Transition from dp[i - 1][0]
dp[i][0] = dp[i - 1][0];
/* 1. Transition from dp[i - 1][1] by just doing
1 extra operation of subtracting 2^i
2. Transition from dp[i - 1][0] by just doing
1 extra operation of subtracting 2^(i+1) */
dp[i][1] = 1 + min(dp[i - 1][1], dp[i - 1][0]);
}
else {
// Transition from dp[i - 1][1]
dp[i][1] = dp[i - 1][1];
/* 1. Transition from dp[i - 1][1] by just doing
1 extra operation of adding 2^(i+1)
2. Transition from dp[i - 1][0] by just doing
1 extra operation of adding 2^i */
dp[i][0] = 1 + min(dp[i - 1][0], dp[i - 1][1]);
}
}
return dp[n - 1][0];
}
// Driver Code
int main()
{
string S = "100";
cout << findMinOperations(S) << endl;
S = "111";
cout << findMinOperations(S) << endl;
return 0;
}
Java
// Java program to find the minimum number
// of operations required to sum to N
class GFG
{
// Function to return the minimum operations required
// to sum to a number reprented by the binary string S
static int findMinOperations(String S)
{
// Reverse the string to consider
// it from LSB to MSB
S = reverse(S);
int n = S.length();
// initialise the dp table
int dp[][] = new int[n + 1][2];
// If S[0] = '0', there is no need to
// perform any operation
if (S.charAt(0) == '0')
{
dp[0][0] = 0;
}
else
{
// If S[0] = '1', just perform a single
// operation(i.e Add 2^0)
dp[0][0] = 1;
}
// Irrespective of the LSB, dp[0][1] is always
// 1 as there is always the need of making the
// suffix of the binary string of the form "11....1"
// as suggested by the definition of dp[i][1]
dp[0][1] = 1;
for (int i = 1; i < n; i++)
{
if (S.charAt(i) == '0')
{
// Transition from dp[i - 1][0]
dp[i][0] = dp[i - 1][0];
/* 1. Transition from dp[i - 1][1] by just doing
1 extra operation of subtracting 2^i
2. Transition from dp[i - 1][0] by just doing
1 extra operation of subtracting 2^(i+1) */
dp[i][1] = 1 + Math.min(dp[i - 1][1], dp[i - 1][0]);
}
else
{
// Transition from dp[i - 1][1]
dp[i][1] = dp[i - 1][1];
/* 1. Transition from dp[i - 1][1] by just doing
1 extra operation of adding 2^(i+1)
2. Transition from dp[i - 1][0] by just doing
1 extra operation of adding 2^i */
dp[i][0] = 1 + Math.min(dp[i - 1][0], dp[i - 1][1]);
}
}
return dp[n - 1][0];
}
static String reverse(String input)
{
char[] temparray = input.toCharArray();
int left, right = 0;
right = temparray.length - 1;
for (left = 0; left < right; left++, right--)
{
// Swap values of left and right
char temp = temparray[left];
temparray[left] = temparray[right];
temparray[right] = temp;
}
return String.valueOf(temparray);
}
// Driver Code
public static void main(String[] args)
{
String S = "100";
System.out.println(findMinOperations(S));
S = "111";
System.out.println(findMinOperations(S));
}
}
// This code is contributed by
// PrinciRaj1992
Python3
# Python3 program to find the minimum
# number of operations required to sum to N
# Function to return the minimum
# operations required to sum to a
# number reprented by the binary string S
def findMinOperations(S) :
# Reverse the string to consider
# it from LSB to MSB
S = S[: : -1]
n = len(S)
# initialise the dp table
dp = [[0] * 2] * (n + 1)
# If S[0] = '0', there is no need
# to perform any operation
if (S[0] == '0') :
dp[0][0] = 0
else :
# If S[0] = '1', just perform a
# single operation(i.e Add 2^0)
dp[0][0] = 1
# Irrespective of the LSB, dp[0][1] is
# always 1 as there is always the need
# of making the suffix of the binary
# string of the form "11....1" as
# suggested by the definition of dp[i][1]
dp[0][1] = 1
for i in range(1, n) :
if (S[i] == '0') :
# Transition from dp[i - 1][0]
dp[i][0] = dp[i - 1][0]
"""
1. Transition from dp[i - 1][1]
by just doing 1 extra operation
of subtracting 2^i
2. Transition from dp[i - 1][0] by
just doing 1 extra operation of
subtracting 2^(i+1)
"""
dp[i][1] = 1 + min(dp[i - 1][1],
dp[i - 1][0])
else :
# Transition from dp[i - 1][1]
dp[i][1] = dp[i - 1][1];
"""
1. Transition from dp[i - 1][1] by
just doing 1 extra operation
of adding 2^(i+1)
2. Transition from dp[i - 1][0] by
just doing 1 extra operation
of adding 2^i
"""
dp[i][0] = 1 + min(dp[i - 1][0],
dp[i - 1][1])
return dp[n - 1][0]
# Driver Code
if __name__ == "__main__" :
S = "100"
print(findMinOperations(S))
S = "111";
print(findMinOperations(S))
# This code is contributed by Ryuga
C#
// C# program to find the minimum number
// of operations required to sum to N
using System;
class GFG
{
// Function to return the minimum
// operations required to sum
// to a number reprented by
// the binary string S
static int findMinOperations(String S)
{
// Reverse the string to consider
// it from LSB to MSB
S = reverse(S);
int n = S.Length;
// initialise the dp table
int [,]dp = new int[n + 1, 2];
// If S[0] = '0', there is no need to
// perform any operation
if (S[0] == '0')
{
dp[0, 0] = 0;
}
else
{
// If S[0] = '1', just perform a single
// operation(i.e Add 2^0)
dp[0, 0] = 1;
}
// Irrespective of the LSB, dp[0,1] is always
// 1 as there is always the need of making the
// suffix of the binary string of the form "11....1"
// as suggested by the definition of dp[i,1]
dp[0, 1] = 1;
for (int i = 1; i < n; i++)
{
if (S[i] == '0')
{
// Transition from dp[i - 1,0]
dp[i, 0] = dp[i - 1, 0];
/* 1. Transition from dp[i - 1,1] by just doing
1 extra operation of subtracting 2^i
2. Transition from dp[i - 1,0] by just doing
1 extra operation of subtracting 2^(i+1) */
dp[i, 1] = 1 + Math.Min(dp[i - 1, 1], dp[i - 1, 0]);
}
else
{
// Transition from dp[i - 1,1]
dp[i, 1] = dp[i - 1, 1];
/* 1. Transition from dp[i - 1,1] by just doing
1 extra operation of adding 2^(i+1)
2. Transition from dp[i - 1,0] by just doing
1 extra operation of adding 2^i */
dp[i, 0] = 1 + Math.Min(dp[i - 1, 0], dp[i - 1, 1]);
}
}
return dp[n - 1, 0];
}
static String reverse(String input)
{
char[] temparray = input.ToCharArray();
int left, right = 0;
right = temparray.Length - 1;
for (left = 0; left < right; left++, right--)
{
// Swap values of left and right
char temp = temparray[left];
temparray[left] = temparray[right];
temparray[right] = temp;
}
return String.Join("",temparray);
}
// Driver Code
public static void Main()
{
String S = "100";
Console.WriteLine(findMinOperations(S));
S = "111";
Console.WriteLine(findMinOperations(S));
}
}
//This code is contributed by 29AjayKumar
PHP
Javascript
1
2
时间复杂度:O(n)
辅助空间:O(n)