📌  相关文章
📜  求和为二进制字符串S 所需的最小运算次数

📅  最后修改于: 2021-09-17 07:28:26             🧑  作者: Mango

给定一个二进制字符串S。求将数字0转换为 S 表示的数字所需的最少操作次数。
允许执行两种类型的操作:

  • 添加2
  • 减去2 x

注意:从 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)