Permutations of capitalization

前端 未结 8 598
生来不讨喜
生来不讨喜 2020-12-21 01:24

I want to build a list containing every possible permutation of capitalization of a word. so it would be

List permutate(string word)
{
    List         


        
相关标签:
8条回答
  • 2020-12-21 01:45

    Assuming:

    1) You don't care too much that this is O(n*2^n)... although I'm curious to know: what is the best asymptotic run time for this type of problem?

    2) Your input is all lowercase.

    3) Your input is < 32 characters long. (# of usable bits in the permutation counter, i)

        List<string> permutate(string word)
    {
        List<string> ret = new List<string>();
    
    // MAGIC HAPPENS HERE
    Dictionary<char,char> toUppers = new Dictionary<char,char>(26);
    toUppers.Add('a', 'A');
    toUppers.Add('b', 'B');
    toUppers.Add('c', 'C');
    toUppers.Add('d', 'D');
    toUppers.Add('e', 'E');
    toUppers.Add('f', 'F');
    toUppers.Add('g', 'G');
    toUppers.Add('h', 'H');
    toUppers.Add('i', 'I');
    toUppers.Add('j', 'J');
    toUppers.Add('k', 'K');
    toUppers.Add('l', 'L');
    toUppers.Add('m', 'M');
    toUppers.Add('n', 'N');
    toUppers.Add('o', 'O');
    toUppers.Add('p', 'P');
    toUppers.Add('q', 'Q');
    toUppers.Add('r', 'R');
    toUppers.Add('s', 'S');
    toUppers.Add('t', 'T');
    toUppers.Add('u', 'U');
    toUppers.Add('v', 'V');
    toUppers.Add('w', 'W');
    toUppers.Add('x', 'X');
    toUppers.Add('y', 'Y');
    toUppers.Add('z', 'Z');
    
    char[] wordChars = word.ToCharArray();
    int len = wordChars.Length;
    
    // iterate the number of permutations
    for(int i = 0; i < 2^len; i++) {
        char[] newWord = new char[len]();
    
        // apply "i" as a bitmask to each original char
        for(int n = 0; n < newWord.Length; n++) {
            if((1 << n) & i != 0) {
                newWord[n] = toUppers[wordChars[n]]; // or skip the dictionary and just call Char.ToUpper(wordChars[n])
            } else {
                newWord[n] = wordChars[n];
            }
        }
        ret.Add(new String(newWord));
    }
    
        return ret;
    }
    

    Note: I haven't compiled or tested this code. This is also implementing the bitwise compare that sharptooth suggested above.

    0 讨论(0)
  • 2020-12-21 01:48

    I was able to create a console app that does this..

     public static class Program
    {
        static void Main()
        {
            Console.WriteLine("Enter string");
            string value = Console.ReadLine();
    
            value = value.ToLower();
    
            List<string> list = new List<string>();
    
             var results =
                 from e in Enumerable.Range(0, 1 << value.Length)
                 let p =
                 from b in Enumerable.Range(0, value.Length)
                 select (e & (1 << b)) == 0 ? (char?)null : value[b]
                 select string.Join(string.Empty, p);
    
            foreach (string s in results)
            {
                string newValue = value;
                s.ToLower();
                foreach(char c in s)
                {
                    var Old = c.ToString().ToLower();
                    var New = c.ToString().ToUpper();
                    newValue=ReplaceFirstOccurrence(newValue, Old, New);
                }
                list.Add(newValue);
            }
    
            foreach(string s in list)
            {
                Console.WriteLine(s);
            }
    
            Console.ReadKey();
        }
    
        public static string ReplaceFirstOccurrence(string Source, string Find, string Replace)
        {
            int Place = Source.IndexOf(Find);
            string result = Source.Remove(Place, Find.Length).Insert(Place, Replace);
            return result;
        }    
    }

    I got a list of all possible subsets of characters in the string then for each character in each subset, replaced them with their capital counterparts in the initial string, then made a list of those. Had to have a custom Replace function as the normal string.Replace would replace any occurrence of the character.

    It's probably not the cleanest of code, but it does the job. This got brought up as a means of dynamically searching over encrypted fields, and I wanted to see how crazy that would really be..

    0 讨论(0)
  • 2020-12-21 01:51

    Loosely speaking, something like below. I may have my ranges off by one, but the idea is sound.

    def cap_n(in_str, pos):
      leading = in_str.substr(0, pos-1)
      trailing = in_str.substr(pos+1) # no second arg implies to end of string
      chr = in_str[pos].to_uppercase()
      return leading + chr + trailing
    
    0 讨论(0)
  • 2020-12-21 01:53

    You can modify individual characters if you convert your string to an array of char. Something like this should do the trick...

    public static List<string> Permute( string s )
    {
      List<string> listPermutations = new List<string>();
    
      char[] array = s.ToLower().ToCharArray();
      int iterations = (1 << array.Length) - 1;
    
      for( int i = 0; i <= iterations; i++ )
      {
        for( int j = 0; j < array.Length; j++ )
        array[j] = (i & (1<<j)) != 0 
                      ? char.ToUpper( array[j] ) 
                      : char.ToLower( array[j] );
        listPermutations.Add( new string( array ) );
      }
      return listPermutations;
    }
    
    0 讨论(0)
  • 2020-12-21 01:58

    Keep in mind that while the accepted answer is the most straightforward way of capitalizing an arbitrary letter, if you are going to change the capitalization repeatedly on the same set of letters (e.g., 32 times in "happy" and growing exponentially for longer words), it will be more efficient to turn the string into a char[], set the appropriate letter(s), and construct the string from the array.

    0 讨论(0)
  • 2020-12-21 01:58

    If order doesn't matter, you can try Linq. We enumerate all binary numbers in a range of [0..2**word.Length]. and treat each number as mask: 0 - lower case, 1 - upper case. For instance for happy we have

    mask      string
    ----------------
    00000  ->  happy
    00001      Happy
    00010      hAppy
    00011      HAppy
    00100      haPpy
    00101      HaPpy
    ...
    11111      HAPPY
    

    Code:

      using System.Linq;
    
      ... 
    
      List<string> permutate(string word) =>
        Enumerable
          .Range(0, 1 << word.Length)
          .Select(mask => string.Concat(word.Select((c, i) => (mask & (1 << i)) == 0 
             ? char.ToLower(c) 
             : char.ToUpper(c))))
          .ToList();
    

    Demo:

      Console.Write(string.Join(", ", permutate("happy")));
    

    Outcome:

    happy, Happy, hAppy, HAppy, haPpy, HaPpy, hAPpy, HAPpy, hapPy, HapPy, hApPy, HApPy, haPPy, HaPPy, hAPPy, HAPPy, happY, HappY, hAppY, HAppY, haPpY, HaPpY, hAPpY, HAPpY, hapPY, HapPY, hApPY, HApPY, haPPY, HaPPY, hAPPY, HAPPY 
    
    0 讨论(0)
提交回复
热议问题