[C#] 문자열 / 정수의 모든 순열 나열

인터뷰 프로그래밍 (일반적으로 인터뷰 경험이 아닌)의 일반적인 작업은 문자열 또는 정수를 사용하여 가능한 모든 순열을 나열하는 것입니다.

이것이 어떻게 수행되는지와 그러한 문제를 해결하는 논리의 예가 있습니까?

몇 가지 코드 스 니펫을 보았지만 주석 처리가 잘되지 않았으므로 따르기가 어렵습니다.



답변

우선 : 물론 재귀 냄새가납니다 !

당신은 또한 그 원리를 알고 싶었 기 때문에 나는 그것을 인간의 언어로 설명하기 위해 최선을 다했습니다. 나는 재귀가 대부분 매우 쉽다고 생각합니다. 두 단계 만 파악하면됩니다.

  1. 첫 번째 단계
  2. 다른 모든 단계 (모두 동일한 논리)

에서 인간의 언어 :

간단히 말해 :
1. 1 요소의 순열은 하나의 요소입니다.
2. 요소 집합의 순열은 각 요소의 목록이며 다른 요소의 모든 순열과 연결됩니다.

예:

세트에 하나의 요소가 있으면
반환하십시오.
파마 (a)-> a

집합에 두 개의 문자가있는 경우 : 각 요소에 대해 다음과 같이 나머지 요소의 순열을 추가하여 요소를 반환하십시오.

파마 (ab)->

a + 파마 (b)-> ab

b + 파마 (a)-> ba

또한 : 세트의 각 문자에 대해 :> 세트의 나머지로 연결된 문자를 반환합니다.

파마 (abc)->

a + perm (bc)-> abc , acb

b + 파마 (ac)-> bac , bca

c + perm (ab)-> 택시 , cba

perm (abc … z)->

a + perm (…), b + perm (….)
….

http://www.programmersheaven.com/mb/Algorithms/369713/369713/permutation-algorithm-help/ 에서 의사 코드 를 찾았습니다 .

makePermutations(permutation) {
  if (length permutation < required length) {
    for (i = min digit to max digit) {
      if (i not in permutation) {
        makePermutations(permutation+i)
      }
    }
  }
  else {
    add permutation to list
  }
}

씨#

OK, http://radio.weblogs.com/0111551/stories/2002/10/14/permutations.html 에서보다 정교한 (그리고 c # 태그가 붙어 있기 때문에) 다소 길지만 복사하기로 결정했습니다. 어쨌든 게시물은 원본에 의존하지 않습니다.

이 함수는 문자열을 가져와 정확한 문자열의 가능한 모든 순열을 기록합니다. 예를 들어 “ABC”가 제공된 경우 유출해야합니다.

ABC, ACB, BAC, BCA, CAB, CBA.

암호:

class Program
{
    private static void Swap(ref char a, ref char b)
    {
        if (a == b) return;

        var temp = a;
        a = b;
        b = temp;
    }

    public static void GetPer(char[] list)
    {
        int x = list.Length - 1;
        GetPer(list, 0, x);
    }

    private static void GetPer(char[] list, int k, int m)
    {
        if (k == m)
        {
            Console.Write(list);
        }
        else
            for (int i = k; i <= m; i++)
            {
                   Swap(ref list[k], ref list[i]);
                   GetPer(list, k + 1, m);
                   Swap(ref list[k], ref list[i]);
            }
    }

    static void Main()
    {
        string str = "sagiv";
        char[] arr = str.ToCharArray();
        GetPer(arr);
    }
}


답변

LINQ를 사용할 수 있으면 두 줄의 코드입니다. 여기에 내 답변을 참조 하십시오 .

편집하다

다음은 T 목록에서 모든 순열 (조합이 아닌)을 반환 할 수있는 일반 함수입니다.

static IEnumerable<IEnumerable<T>>
    GetPermutations<T>(IEnumerable<T> list, int length)
{
    if (length == 1) return list.Select(t => new T[] { t });

    return GetPermutations(list, length - 1)
        .SelectMany(t => list.Where(e => !t.Contains(e)),
            (t1, t2) => t1.Concat(new T[] { t2 }));
}

예:

IEnumerable<IEnumerable<int>> result =
    GetPermutations(Enumerable.Range(1, 3), 3);

출력-정수 목록 :

{1,2,3} {1,3,2} {2,1,3} {2,3,1} {3,1,2} {3,2,1}

이 함수는 LINQ를 사용하므로 .net 3.5 이상이 필요합니다.


답변

여기에서 해결책을 찾았습니다. Java로 작성되었지만 C #으로 변환했습니다. 도움이 되길 바랍니다.

여기에 이미지 설명을 입력하십시오

C #의 코드는 다음과 같습니다.

static void Main(string[] args)
{
    string str = "ABC";
    char[] charArry = str.ToCharArray();
    Permute(charArry, 0, 2);
    Console.ReadKey();
}

static void Permute(char[] arry, int i, int n)
{
    int j;
    if (i==n)
        Console.WriteLine(arry);
    else
    {
        for(j = i; j <=n; j++)
        {
            Swap(ref arry[i],ref arry[j]);
            Permute(arry,i+1,n);
            Swap(ref arry[i], ref arry[j]); //backtrack
        }
    }
}

static void Swap(ref char a, ref char b)
{
    char tmp;
    tmp = a;
    a=b;
    b = tmp;
}


답변

재귀 는 필요하지 않습니다. 여기 에이 솔루션에 대한 좋은 정보가 있습니다.

var values1 = new[] { 1, 2, 3, 4, 5 };

foreach (var permutation in values1.GetPermutations())
{
    Console.WriteLine(string.Join(", ", permutation));
}

var values2 = new[] { 'a', 'b', 'c', 'd', 'e' };

foreach (var permutation in values2.GetPermutations())
{
    Console.WriteLine(string.Join(", ", permutation));
}

Console.ReadLine();

나는 수년 동안이 알고리즘을 사용해 왔으며 각 순열 을 계산하기 위해 O (N) 시간공간이 복잡합니다 .

public static class SomeExtensions
{
    public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> enumerable)
    {
        var array = enumerable as T[] ?? enumerable.ToArray();

        var factorials = Enumerable.Range(0, array.Length + 1)
            .Select(Factorial)
            .ToArray();

        for (var i = 0L; i < factorials[array.Length]; i++)
        {
            var sequence = GenerateSequence(i, array.Length - 1, factorials);

            yield return GeneratePermutation(array, sequence);
        }
    }

    private static IEnumerable<T> GeneratePermutation<T>(T[] array, IReadOnlyList<int> sequence)
    {
        var clone = (T[]) array.Clone();

        for (int i = 0; i < clone.Length - 1; i++)
        {
            Swap(ref clone[i], ref clone[i + sequence[i]]);
        }

        return clone;
    }

    private static int[] GenerateSequence(long number, int size, IReadOnlyList<long> factorials)
    {
        var sequence = new int[size];

        for (var j = 0; j < sequence.Length; j++)
        {
            var facto = factorials[sequence.Length - j];

            sequence[j] = (int)(number / facto);
            number = (int)(number % facto);
        }

        return sequence;
    }

    static void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }

    private static long Factorial(int n)
    {
        long result = n;

        for (int i = 1; i < n; i++)
        {
            result = result * i;
        }

        return result;
    }
}


답변

void permute (char *str, int ptr) {
  int i, len;
  len = strlen(str);
  if (ptr == len) {
    printf ("%s\n", str);
    return;
  }

  for (i = ptr ; i < len ; i++) {
    swap (&str[ptr], &str[i]);
    permute (str, ptr + 1);
    swap (&str[ptr], &str[i]);
  }
}

교체 기능을 작성하여 문자를 교체 할 수 있습니다.
이것은 permute (string, 0);


답변

우선, 집합에는 문자열이나 정수가 아닌 순열이 있으므로 “문자열의 문자 집합”을 의미한다고 가정하겠습니다.

크기 n의 집합에는 n이 있습니다! n 순열.

k = 1 … n으로 호출 된 다음 의사 코드 (Wikipedia에서)! 모든 순열을 제공합니다.

function permutation(k, s) {
    for j = 2 to length(s) {
        swap s[(k mod j) + 1] with s[j]; // note that our array is indexed starting at 1
        k := k / j; // integer division cuts off the remainder
    }
    return s;
}

다음은 동등한 파이썬 코드입니다 (0 기반 배열 인덱스 용).

def permutation(k, s):
    r = s[:]
    for j in range(2, len(s)+1):
        r[j-1], r[k%j] = r[k%j], r[j-1]
        k = k/j+1
    return r


답변

C #에서 약간 수정 된 버전으로, 모든 유형의 배열에서 필요한 순열이 생성됩니다.

    // USAGE: create an array of any type, and call Permutations()
    var vals = new[] {"a", "bb", "ccc"};
    foreach (var v in Permutations(vals))
        Console.WriteLine(string.Join(",", v)); // Print values separated by comma


public static IEnumerable<T[]> Permutations<T>(T[] values, int fromInd = 0)
{
    if (fromInd + 1 == values.Length)
        yield return values;
    else
    {
        foreach (var v in Permutations(values, fromInd + 1))
            yield return v;

        for (var i = fromInd + 1; i < values.Length; i++)
        {
            SwapValues(values, fromInd, i);
            foreach (var v in Permutations(values, fromInd + 1))
                yield return v;
            SwapValues(values, fromInd, i);
        }
    }
}

private static void SwapValues<T>(T[] values, int pos1, int pos2)
{
    if (pos1 != pos2)
    {
        T tmp = values[pos1];
        values[pos1] = values[pos2];
        values[pos2] = tmp;
    }
}