Taro Logo

Minimum Number of Changes to Make Binary String Beautiful

Medium
Adobe logo
Adobe
0 views
Topics:
StringsGreedy Algorithms

You are given a 0-indexed binary string s having an even length.

A string is beautiful if it's possible to partition it into one or more substrings such that:

  • Each substring has an even length.
  • Each substring contains only 1's or only 0's.

You can change any character in s to 0 or 1.

Return the minimum number of changes required to make the string s beautiful.

Example 1:

Input: s = "1001"
Output: 2
Explanation: We change s[1] to 1 and s[3] to 0 to get string "1100".
It can be seen that the string "1100" is beautiful because we can partition it into "11|00".
It can be proven that 2 is the minimum number of changes needed to make the string beautiful.

Example 2:

Input: s = "10"
Output: 1
Explanation: We change s[1] to 1 to get string "11".
It can be seen that the string "11" is beautiful because we can partition it into "11".
It can be proven that 1 is the minimum number of changes needed to make the string beautiful.

Example 3:

Input: s = "0000"
Output: 0
Explanation: We don't need to make any changes as the string "0000" is beautiful already.

Constraints:

  • 2 <= s.length <= 105
  • s has an even length.
  • s[i] is either '0' or '1'.

Solution


Clarifying Questions

When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:

  1. What are the allowed characters in the binary string (only '0' and '1')?
  2. What constitutes a 'beautiful' binary string? Specifically, should adjacent substrings of length 2 be equal, or is there another condition I should consider?
  3. What is the maximum length of the input binary string?
  4. If the input string is null or empty, what should be the return value?
  5. Are we looking for the minimum number of *changes* (flipping a bit) or the minimum number of *operations* (which might include other transformations)? I am assuming changes means flipping a bit.

Brute Force Solution

Approach

The brute force method involves trying every possible way to modify the binary string to make it beautiful. This means we consider all combinations of changes and then select the one that requires the fewest alterations. In essence, we explore all potential solutions to find the best one.

Here's how the algorithm would work step-by-step:

  1. Consider making no changes at all to the string and check if the string is already beautiful.
  2. Now, imagine changing only the first character of the string, and see if that makes it beautiful.
  3. Next, try changing only the second character, only the third character, and so on, one at a time.
  4. Now, explore changing two characters at a time: the first and second, the first and third, the second and third, and so on.
  5. Continue this process, considering changing three characters at a time, then four, and so on, all the way up to changing every single character in the string.
  6. For each combination of changes you make, carefully check if the resulting string is now beautiful.
  7. Count how many changes were needed for each way you made the string beautiful.
  8. Finally, pick the method that required the fewest changes of all the ways you found to make the string beautiful.

Code Implementation

def minimum_changes_brute_force(binary_string):
    string_length = len(binary_string)
    minimum_changes_needed = string_length

    for i in range(2 ** string_length):
        modified_string = list(binary_string)
        changes_count = 0

        # Iterate over bits to determine which characters to flip
        for j in range(string_length):
            if (i >> j) & 1:
                modified_string[j] = '1' if modified_string[j] == '0' else '0'
                changes_count += 1

        modified_string = "".join(modified_string)

        # Check if modified string is beautiful
        is_beautiful = True
        for k in range(0, string_length - 1, 2):
            if modified_string[k] != modified_string[k+1]:
                is_beautiful = False
                break

        # Update minimum changes if string is beautiful
        if is_beautiful:
            minimum_changes_needed = min(minimum_changes_needed, changes_count)

    return minimum_changes_needed

Big(O) Analysis

Time Complexity
O(2^n * n)The brute force approach considers all possible subsets of characters to change. There are 2^n such subsets. For each subset, we need to change those characters, which takes O(n) time in the worst case to copy or modify the string. Then, we also need to check if the resulting string is 'beautiful', and this check requires iterating through the entire string of length n. Therefore, the total time complexity is O(2^n * n).
Space Complexity
O(N)The brute force method, as described, explores all possible combinations of changes to the binary string. It implicitly creates modified copies of the input string to check if a particular combination of changes makes the string beautiful. In the worst case, especially when exploring all possible character changes, a copy of the string of size N (where N is the length of the input string) will be created. The algorithm must at least create one copy to modify and test, or store a list of indices of size N to indicate what to flip, which would then be applied to a full copy of the string. Therefore, the auxiliary space complexity is O(N).

Optimal Solution

Approach

The best way to solve this is to walk through the string and fix pairs of characters as needed. We focus on each pair and change only what's absolutely necessary to make them fit the beautiful pattern.

Here's how the algorithm would work step-by-step:

  1. Look at the string in pairs of characters.
  2. For each pair, check if the two characters are different.
  3. If the characters are different, we need to change one of them to make them the same.
  4. To minimize changes, always change the second character in the pair.
  5. Keep a running count of how many changes you make.
  6. After checking all pairs, the change count will be the minimum number of changes needed.

Code Implementation

def min_changes(binary_string):
    number_of_changes = 0
    string_length = len(binary_string)

    for i in range(0, string_length - 1, 2):
        # Iterate through the string, examining pairs.
        if binary_string[i] != binary_string[i+1]:

            #The pair differs, so change the second character.
            number_of_changes += 1

    return number_of_changes

Big(O) Analysis

Time Complexity
O(n)The algorithm iterates through the binary string of size n, examining pairs of characters. For each pair, it performs a constant-time comparison to determine if the characters are different and potentially makes a single change, which is also a constant-time operation. Since the number of pairs is directly proportional to the input size n (specifically, n/2), the overall time complexity is O(n).
Space Complexity
O(1)The provided solution iterates through the input string, operating on pairs of characters. It maintains a single integer variable to count the changes made. No additional data structures, such as arrays, hash maps, or trees, are created or used. Therefore, the auxiliary space used remains constant regardless of the input string's length, N.

Edge Cases

CaseHow to Handle
Empty string inputReturn 0 as no changes are needed for an empty string since it's already 'beautiful'.
String with a single characterReturn 0 since a single character cannot form an adjacent pair and is considered 'beautiful'.
String with all identical characters (e.g., '0000')Return string length / 2, ensuring integer division to get the correct number of changes.
String with alternating characters (e.g., '0101')Return 0 since no changes are needed because it is already beautiful.
Very long string (potential for performance issues)The iterative solution has linear time complexity O(n), so it should scale efficiently for very long strings.
String with only '0' characters repeated many timesThis is a special case of all identical characters; divide the string length by 2 to get the result.
String with only '1' characters repeated many timesThis is a special case of all identical characters; divide the string length by 2 to get the result.
String with even length and all characters at odd indices are the same, and all even indices are the same, but they don't alternate.The standard iterative process accounts for this by comparing adjacent characters and incrementing a counter as needed.