Open In App

Two-Color Sorting

Given a string s consisting of n lowercase letters. You have to color all of its characters using two colors such that each index of s is assigned exactly one color. You can swap two adjacent indexes of s that have different colors any number of times. The task is to determine whether you can sort the strings or not.

Examples:



Input: n = 9, s = abacbecfd
Output: YES
001010101

Input: 8, s = aaabbcbb
Output: YES
01011011



Approach: To solve the problem follow the below idea:

The idea is to use dynamic programming to determine if it is possible to color a given string such that, through swaps of adjacent differently colored characters, the string becomes sorted. It assigns colors based on the alphabetical order, considering adjacent characters and their possible colorings, and then reconstructs the valid coloring by backtracking from the last character. The final result indicates whether sorting is achievable, and if so, provides a valid coloring of the string.

Step-by-step approach:

Below is the implementation of the above approach:




#include <bits/stdc++.h>
using namespace std;
 
const int MaxLength = 222; // Maximum length of the string
const int AlphabetSize = 26; // Size of the Latin alphabet
 
bool dp[MaxLength][AlphabetSize][AlphabetSize];
pair<pair<int, int>, int> parent[MaxLength][AlphabetSize]
                                [AlphabetSize];
 
int main()
{
    int n = 9;
    string s = "abacbecfd";
 
    // Dynamic programming initialization
    dp[0][0][0] = 1;
 
    for (int i = 0; i < n; ++i) {
        int currentChar = s[i] - 'a';
 
        // Iterate over possible colors for adjacent
        // characters
        for (int color1 = 0; color1 < AlphabetSize;
             ++color1) {
            for (int color2 = 0; color2 < AlphabetSize;
                 ++color2) {
                if (!dp[i][color1][color2])
                    continue;
 
                // Check conditions for assigning colors and
                // update DP states
                if (currentChar >= color1) {
                    dp[i + 1][currentChar][color2] = 1;
                    parent[i + 1][currentChar][color2]
                        = make_pair(
                            make_pair(color1, color2), 0);
                }
 
                if (currentChar >= color2) {
                    dp[i + 1][color1][currentChar] = 1;
                    parent[i + 1][color1][currentChar]
                        = make_pair(
                            make_pair(color1, color2), 1);
                }
            }
        }
    }
 
    int lastColor1 = -1, lastColor2 = -1;
 
    // Find possible colors for the last character
    for (int color1 = 0; color1 < AlphabetSize; ++color1) {
        for (int color2 = 0; color2 < AlphabetSize;
             ++color2) {
            if (dp[n][color1][color2]) {
                lastColor1 = color1;
                lastColor2 = color2;
            }
        }
    }
 
    // If no valid colors found, print "NO"
    if (lastColor1 == -1) {
        cout << "NO" << endl;
        return 0;
    }
 
    // Reconstruct the coloring
    string coloring;
    for (int i = n; i > 0; --i) {
        int prevColor1
            = parent[i][lastColor1][lastColor2].first.first;
        int prevColor2 = parent[i][lastColor1][lastColor2]
                             .first.second;
 
        if (parent[i][lastColor1][lastColor2].second) {
            coloring += '1';
        }
        else {
            coloring += '0';
        }
 
        lastColor1 = prevColor1;
        lastColor2 = prevColor2;
    }
 
    reverse(coloring.begin(), coloring.end());
 
    // Print the result
    cout << "YES" << endl << coloring << endl;
 
    return 0;
}




import java.util.*;
 
public class ColoringString {
    static final int MaxLength = 222;
    static final int AlphabetSize = 26;
 
    static boolean[][][] dp
        = new boolean[MaxLength][AlphabetSize]
                     [AlphabetSize];
    static int[][][] parent
        = new int[MaxLength][AlphabetSize][AlphabetSize];
 
    public static void main(String[] args)
    {
        int n = 9;
        String s = "abacbecfd";
 
        // Dynamic programming initialization
        dp[0][0][0] = true;
 
        for (int i = 0; i < n; ++i) {
            int currentChar = s.charAt(i) - 'a';
 
            // Iterate over possible colors for adjacent
            // characters
            for (int color1 = 0; color1 < AlphabetSize;
                 ++color1) {
                for (int color2 = 0; color2 < AlphabetSize;
                     ++color2) {
                    if (!dp[i][color1][color2])
                        continue;
 
                    // Check conditions for assigning colors
                    // and update DP states
                    if (currentChar >= color1) {
                        dp[i + 1][currentChar][color2]
                            = true;
                        parent[i + 1][currentChar][color2]
                            = color1;
                    }
 
                    if (currentChar >= color2) {
                        dp[i + 1][color1][currentChar]
                            = true;
                        parent[i + 1][color1][currentChar]
                            = color2 + AlphabetSize;
                    }
                }
            }
        }
 
        int lastColor1 = -1, lastColor2 = -1;
 
        // Find possible colors for the last character
        for (int color1 = 0; color1 < AlphabetSize;
             ++color1) {
            for (int color2 = 0; color2 < AlphabetSize;
                 ++color2) {
                if (dp[n][color1][color2]) {
                    lastColor1 = color1;
                    lastColor2 = color2;
                }
            }
        }
 
        // If no valid colors found, print "NO"
        if (lastColor1 == -1) {
            System.out.println("NO");
            return;
        }
 
        // Reconstruct the coloring
        StringBuilder coloring = new StringBuilder();
        for (int i = n; i > 0; --i) {
            int prevColor
                = parent[i][lastColor1][lastColor2];
 
            if (prevColor >= AlphabetSize) {
                coloring.append('1');
                lastColor2 = prevColor - AlphabetSize;
            }
            else {
                coloring.append('0');
                lastColor1 = prevColor;
            }
        }
 
        coloring.reverse();
 
        // Print the result
        System.out.println("YES");
        System.out.println(coloring);
    }
}




MaxLength = 222  # Maximum length of the string
AlphabetSize = 26  # Size of the Latin alphabet
 
# Dynamic programming initialization
dp = [[[False for _ in range(AlphabetSize)] for _ in range(AlphabetSize)] for _ in range(MaxLength)]
parent = [[[[(0, 0), 0] for _ in range(AlphabetSize)] for _ in range(AlphabetSize)] for _ in range(MaxLength)]
 
n = 9
s = "abacbecfd"
 
# Initialize DP
dp[0][0][0] = True
 
for i in range(n):
    currentChar = ord(s[i]) - ord('a')
 
    # Iterate over possible colors for adjacent characters
    for color1 in range(AlphabetSize):
        for color2 in range(AlphabetSize):
            if not dp[i][color1][color2]:
                continue
 
            # Check conditions for assigning colors and update DP states
            if currentChar >= color1:
                dp[i + 1][currentChar][color2] = True
                parent[i + 1][currentChar][color2] = ((color1, color2), 0)
 
            if currentChar >= color2:
                dp[i + 1][color1][currentChar] = True
                parent[i + 1][color1][currentChar] = ((color1, color2), 1)
 
lastColor1, lastColor2 = -1, -1
 
# Find possible colors for the last character
for color1 in range(AlphabetSize):
    for color2 in range(AlphabetSize):
        if dp[n][color1][color2]:
            lastColor1, lastColor2 = color1, color2
 
# If no valid colors found, print "NO"
if lastColor1 == -1:
    print("NO")
else:
    # Reconstruct the coloring
    coloring = ""
    for i in range(n, 0, -1):
        prevColor1, prevColor2 = parent[i][lastColor1][lastColor2][0]
 
        if parent[i][lastColor1][lastColor2][1]:
            coloring += '1'
        else:
            coloring += '0'
 
        lastColor1, lastColor2 = prevColor1, prevColor2
 
    # Print the result
    print("YES")
    print(coloring[::-1])




using System;
 
class Program
{
    const int MaxLength = 222; // Maximum length of the string
    const int AlphabetSize = 26; // Size of the Latin alphabet
 
    static bool[,,] dp = new bool[MaxLength, AlphabetSize, AlphabetSize];
    static Tuple<Tuple<int, int>, int>[,,] parent = new Tuple<Tuple<int, int>, int>[MaxLength, AlphabetSize, AlphabetSize];
 
    static void Main()
    {
        int n = 9;
        string s = "abacbecfd";
 
        // Dynamic programming initialization
        dp[0, 0, 0] = true;
 
        for (int i = 0; i < n; ++i)
        {
            int currentChar = s[i] - 'a';
 
            // Iterate over possible colors for adjacent characters
            for (int color1 = 0; color1 < AlphabetSize; ++color1)
            {
                for (int color2 = 0; color2 < AlphabetSize; ++color2)
                {
                    if (!dp[i, color1, color2])
                        continue;
 
                    // Check conditions for assigning colors and update DP states
                    if (currentChar >= color1)
                    {
                        dp[i + 1, currentChar, color2] = true;
                        parent[i + 1, currentChar, color2] = new Tuple<Tuple<int, int>, int>(new Tuple<int, int>(color1, color2), 0);
                    }
 
                    if (currentChar >= color2)
                    {
                        dp[i + 1, color1, currentChar] = true;
                        parent[i + 1, color1, currentChar] = new Tuple<Tuple<int, int>, int>(new Tuple<int, int>(color1, color2), 1);
                    }
                }
            }
        }
 
        int lastColor1 = -1, lastColor2 = -1;
 
        // Find possible colors for the last character
        for (int color1 = 0; color1 < AlphabetSize; ++color1)
        {
            for (int color2 = 0; color2 < AlphabetSize; ++color2)
            {
                if (dp[n, color1, color2])
                {
                    lastColor1 = color1;
                    lastColor2 = color2;
                }
            }
        }
 
        // If no valid colors found, print "NO"
        if (lastColor1 == -1)
        {
            Console.WriteLine("NO");
            return;
        }
 
        // Reconstruct the coloring
        string coloring = "";
        for (int i = n; i > 0; --i)
        {
            int prevColor1 = parent[i, lastColor1, lastColor2].Item1.Item1;
            int prevColor2 = parent[i, lastColor1, lastColor2].Item1.Item2;
 
            if (parent[i, lastColor1, lastColor2].Item2 == 1)
            {
                coloring += '1';
            }
            else
            {
                coloring += '0';
            }
 
            lastColor1 = prevColor1;
            lastColor2 = prevColor2;
        }
 
        char[] reversedColoring = coloring.ToCharArray();
        Array.Reverse(reversedColoring);
        coloring = new string(reversedColoring);
 
        // Print the result
        Console.WriteLine("YES");
        Console.WriteLine(coloring);
    }
}




const MaxLength = 222;
const AlphabetSize = 26;
 
const dp = new Array(MaxLength)
    .fill(false)
    .map(() =>
        new Array(AlphabetSize)
            .fill(false)
            .map(() => new Array(AlphabetSize).fill(false))
    );
 
const parent = new Array(MaxLength)
    .fill(0)
    .map(() => new Array(AlphabetSize).fill(0).map(() => new Array(AlphabetSize).fill(0)));
 
function main() {
    const n = 9;
    const s = "abacbecfd";
 
    // Dynamic programming initialization
    dp[0][0][0] = true;
 
    for (let i = 0; i < n; ++i) {
        const currentChar = s.charCodeAt(i) - 'a'.charCodeAt(0);
 
        // Iterate over possible colors for adjacent characters
        for (let color1 = 0; color1 < AlphabetSize; ++color1) {
            for (let color2 = 0; color2 < AlphabetSize; ++color2) {
                if (!dp[i][color1][color2]) continue;
 
                // Check conditions for assigning colors
                // and update DP states
                if (currentChar >= color1) {
                    dp[i + 1][currentChar][color2] = true;
                    parent[i + 1][currentChar][color2] = color1;
                }
 
                if (currentChar >= color2) {
                    dp[i + 1][color1][currentChar] = true;
                    parent[i + 1][color1][currentChar] = color2 + AlphabetSize;
                }
            }
        }
    }
 
    let lastColor1 = -1, lastColor2 = -1;
 
    // Find possible colors for the last character
    for (let color1 = 0; color1 < AlphabetSize; ++color1) {
        for (let color2 = 0; color2 < AlphabetSize; ++color2) {
            if (dp[n][color1][color2]) {
                lastColor1 = color1;
                lastColor2 = color2;
            }
        }
    }
 
    // If no valid colors found, print "NO"
    if (lastColor1 === -1) {
        console.log("NO");
        return;
    }
 
    // Reconstruct the coloring
    let coloring = '';
    for (let i = n; i > 0; --i) {
        const prevColor = parent[i][lastColor1][lastColor2];
 
        if (prevColor >= AlphabetSize) {
            coloring += '1';
            lastColor2 = prevColor - AlphabetSize;
        } else {
            coloring += '0';
            lastColor1 = prevColor;
        }
    }
 
    // Print the result
    console.log("YES");
    console.log(coloring.split('').reverse().join(''));
}
 
// Call the main function
main();

Output
YES
101100101











Time complexity: O(n * AL^2), where n is the length of the string and AL is the size of the Latin alphabet (26).
Auxiliary space: O(n * AL^2)


Article Tags :