-2

I have the following code: given a string with length m, add '-' to any possible position (including between different chars of original string) to extend it to length n. For example, given "ABC", extend it to 6. It will be "---ABC", "--A-BC", "--AB-C", "--ABC-", ......, "AB---C", "ABC---".

class Program
{
    // <summary>
    /// Grow a string to desired length with time limitation
    /// </summary>
    /// <param name="s"></param>
    /// <param name="length"></param>
    /// <param name="pad"></param>
    /// <param name="Padded"></param>
    public static bool ExtendToLen(string s, int length, char pad, ref List<string> Padded, ref Stopwatch timer, int timeOut)
    {
        if (s.Length == length)
        {
            Padded.Add(s);
            return true;
        }
        else if (s.Length > length)
        {
            return true;
        }
        else
        {
            List<int> pos = GetExceptPos(s, pad.ToString());
            pos.Sort();

            int count = -1;
            foreach (int p in pos)
            {
                if (timer.Elapsed.TotalSeconds > timeOut)
                {
                    return false;
                }

                //Debug.WriteLine(string.Format("pos:{0}", p), "PadToLength");
                count++;

                // Pad left 
                string leftPadStr = s.Substring(0, p) + pad + s.Substring(p);
                //Debug.WriteLine(string.Format("\tLeftPadStr:{0}", leftPadStr));
                bool go = ExtendToLen(leftPadStr, length, pad, ref Padded, ref timer, timeOut);
                if (go == false) { return false; }

                // Pad right at the last pos
                if (count == pos.Count - 1)
                {
                    string rightPadStr = s + pad;
                    go = ExtendToLen(rightPadStr, length, pad, ref Padded, ref timer, timeOut);
                    if (go == false) { return false; }
                }
            }
            return true;
        }
    }

    /// <summary>
    /// Find indexes of elements different from target str
    /// </summary>
    /// <param name="str"></param>
    /// <param name="excludeStr"></param>
    /// <returns></returns>
    private static List<int> GetExceptPos(string str, string excludeStr)
    {
        List<int> allIndexes = new List<int>();
        for (int i = 0; i < str.Length; i++)
        {
            allIndexes.Add(i);
        }

        return allIndexes.Except(str.IndexesOf(excludeStr)).ToList();
    }

    static void Main(string[] args)
    {
        string old = "ACGUA";
        List<string> newList = new List<string>();
        Stopwatch timer = new Stopwatch();
        timer.Start();
        bool isGood = ExtendToLen(old, 12, '-', ref newList, ref timer, 100);
        timer.Stop();

        foreach (string s in newList)
        {
            Console.WriteLine(s);
        }

        Console.WriteLine("Elapsed time: {0}", timer.Elapsed);
        Console.ReadLine();
    }
}

public static class ExtensionMethods
{
    /// <summary>
    /// Return all indeces
    /// </summary>
    /// <param name="haystack"></param>
    /// <param name="needle"></param>
    /// <returns></returns>
    public static IEnumerable<int> IndexesOf(this string haystack, string needle)
    {
        int lastIndex = 0;
        while (true)
        {
            int index = haystack.IndexOf(needle, lastIndex);
            if (index == -1)
            {
                yield break;
            }
            yield return index;
            lastIndex = index + needle.Length;
        }
    }
}

It runs slowly, for example, if I want to extend a string (len = 5) to 20, it runs long long long time. And the result seems to be redundant.

So the question is how to speed it up and remove those redundancy.

Any suggestion will be appreciated.

svick
  • 236,525
  • 50
  • 385
  • 514
Mavershang
  • 1,266
  • 2
  • 15
  • 27
  • 2
    You are aware there are `PadLeft` and `PadRight` methods for `string`.. yes? – Simon Whitehead Feb 19 '13 at 00:01
  • @Simon: it is not a padleft or padRight, I also need to insert '-' between chars in the original string – Mavershang Feb 19 '13 at 00:03
  • You haven't mentioned that in your question. Please update it. The way your question reads at the moment, this: `Console.WriteLine(old.PadRight(12, '-'));` is all you're after... which executes in milliseconds. – Simon Whitehead Feb 19 '13 at 00:04
  • 1
    Not sure what are your expectations - for any reasonable size of the string number of combinations is huge so it will take long time to generate all: "how many ways to put `length` items in `padding` number of buckets" is some combination of factorials... – Alexei Levenkov Feb 19 '13 at 00:11
  • Side note: please update title so it is clear that you need list of *all* permutations. – Alexei Levenkov Feb 19 '13 at 00:12
  • Possibly related: http://stackoverflow.com/questions/4174926/how-to-get-all-combination-of-an-arraylist – Abe Miessler Feb 19 '13 at 00:19
  • The basic problem here is that your code treats as unique adding a pad into position #1, #2 from #2, #1. Unless I'm messing up the math this function can't terminate on any normal PC--it's going to run out of memory first. – Loren Pechtel Feb 19 '13 at 00:38

1 Answers1

0

This is a very rough hack and should get you started.

It basically moves the string backwards through your padding one character at a time.

static unsafe void performPaddedBubbleSort(string s, char c, int padCount, IList<string> list) {
        s = new string(c, padCount) + s;
        bool complete = false;
        int index = 0;
        int count = 0;
        fixed (char* p = s) {
            while (count < s.Length && *p == c) {
                while (index < s.Length) {
                    if (*(p + index) != c) {
                        // flip them
                        char tempChar = *(p + index);
                        if (index != 0)
                            *((p + index) - 1) = tempChar;
                        *(p + index) = c;

                        list.Add(new string(p));
                    }

                    index++;
                }
                index = 0;
                count++;
            }
        }
    }

Input of "ABC" with padding of 3 (to make it 6 chars wide) is:

--A-BC
--AB-C
--ABC-
-A-BC-
-AB-C-
-ABC--
A-BC--
AB-C--
ABC---
Elapsed time: 00:00:00.0008663

Not sure if that's exactly what you were after.. but its a start I guess. As you can see it executes in a fraction of a second.

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138