0

I'm preparing for my interview, faced the problem with the task. The case is that we're having a string: test12pop90java989python

I need to return new string where words will be reversed and numbers will stay in the same place:

test12pop90java989python ==> tset12pop90avaj989nohtyp

What I started with:

  1. Transferring string to char array

  2. Use for loop + Char.IsNumber

  3. ??

     var charArray = test.ToCharArray();
     for (int i = 0; i < charArray.Length; i++)
     {
         if (!Char.IsNumber(charArray[i]))
         {
         ....
         }
     }
    

but currently I'm stuck and don't know how to proceed, any tips how it can be done?

1

3 Answers 3

3

You can't reverse a run of letters until you've observed the entire run; until then, you need to keep track of the pending letters to be reversed and appended to the final output upon encountering a number or the end of the string. By storing these pending characters in a Stack<> they are naturally returned in the reverse order they were added.

static string Transform(string input)
{
    StringBuilder outputBuilder = new StringBuilder(input.Length);
    Stack<char> pending = new Stack<char>();

    foreach (char c in input)
        if (char.IsNumber(c))
        {
            // In the reverse order of which they were added, consume
            // and append pending characters as long as they are available
            while (pending.Count > 0)
                outputBuilder.Append(pending.Pop());

            // Alternatively...
            //foreach (char p in pending)
            //  outputBuilder.Append(p);
            //pending.Clear();

            outputBuilder.Append(c);
        }
        else
            pending.Push(c);

    // Handle pending characters when input does not end with a number
    while (pending.Count > 0)
        outputBuilder.Append(pending.Pop());

    return outputBuilder.ToString();
}

A similar but buffer-free way is to do it is to store the index of the start of the current run of letters, then walk back through and append each character when a number is found...

static string Transform(string input)
{
    StringBuilder outputBuilder = new StringBuilder(input.Length);
    int lettersStartIndex = -1;

    for (int i = 0; i < input.Length; i++)
    {
        char c = input[i];

        if (char.IsNumber(c))
        {
            if (lettersStartIndex >= 0)
            {
                // Iterate backwards from the previous character to the start of the run
                for (int j = i - 1; j >= lettersStartIndex; j--)
                    outputBuilder.Append(input[j]);
                lettersStartIndex = -1;
            }

            outputBuilder.Append(c);
        }
        else if (lettersStartIndex < 0)
            lettersStartIndex = i;
    }

    // Handle remaining characters when input does not end with a number
    if (lettersStartIndex >= 0)
        for (int j = input.Length - 1; j >= lettersStartIndex; j--)
            outputBuilder.Append(input[j]);

    return outputBuilder.ToString();
}

For both implementations, calling Transform() with...

string[] inputs = new string[] {
    "test12pop90java989python",
    "123test12pop90java989python321",
    "This text contains no numbers",
    "1a2b3c"
};

for (int i = 0; i < inputs.Length; i++)
{
    string input = inputs[i];
    string output = Transform(input);

    Console.WriteLine($" Input[{i}]: \"{input }\"");
    Console.WriteLine($"Output[{i}]: \"{output}\"");
    Console.WriteLine();
}

...produces this output...

 Input[0]: "test12pop90java989python"
Output[0]: "tset12pop90avaj989nohtyp"

 Input[1]: "123test12pop90java989python321"
Output[1]: "123tset12pop90avaj989nohtyp321"

 Input[2]: "This text contains no numbers"
Output[2]: "srebmun on sniatnoc txet sihT"

 Input[3]: "1a2b3c"
Output[3]: "1a2b3c"
Sign up to request clarification or add additional context in comments.

2 Comments

Just in case the OP in on .NET Framework, TryPop is alien. Just .Push and .Clear after appending the StringBuilder. And you don't need a loop to append, just call outputBuilder.Append(pending.ToArray());
I did something like that before, but changed it to avoid the array allocation. Good point on TryPop() and for reminding there's an overload of Append() that takes a char[].
2

A possible solution using Regex and Linq:

using System;
using System.Text.RegularExpressions;
using System.Linq;
                
public class Program
{
    public static void Main()
    {
        var result = "";
        var matchList = Regex.Matches("test12pop90java989python", "([a-zA-Z]*)(\\d*)");
        var list = matchList.Cast<Match>().SelectMany(o =>o.Groups.Cast<Capture>().Skip(1).Select(c => c.Value));
        foreach (var el in list)
        {
            if (el.All(char.IsDigit))
            {
                result += el;
            }
            else
            {
                result += new string(el.Reverse().ToArray());
            }
        }

        Console.WriteLine(result);
    }
}

I've used code from stackoverflow.com/a/21123574/1037948 to create a list of Regex matches on line 11:

var list = matchList.Cast<Match>().SelectMany(o =>o.Groups.Cast<Capture>().Skip(1).Select(c => c.Value));

Comments

2

Hey you can do something like:

string test = "test12pop90java989python", tempStr = "", finalstr = "";
            var charArray = test.ToCharArray();

            for (int i = 0; i < charArray.Length; i++)
            {
                if (!Char.IsNumber(charArray[i]))
                {
                    tempStr += charArray[i];
                }
                else
                {
                    char[] ReverseString = tempStr.Reverse().ToArray();
                    foreach (char charItem in ReverseString)
                    {
                        finalstr += charItem;
                    }

                    tempStr = "";
                    finalstr += charArray[i];
                }
            }

            if(tempStr != "" && tempStr != null)
            {
                char[] ReverseString = tempStr.Reverse().ToArray();
                foreach (char charItem in ReverseString)
                {
                    finalstr += charItem;
                }

                tempStr = "";
            }

I hope this helps

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.