具有常数前缀数字的排列

时间:2017-08-26 12:47:35

标签: c#

我有一个整数数组,其中每个值都有不同的含义。第一个值表示排列长度,第二个值表示初始前缀的长度,其余整数是构成所有排列前缀的单个整数。

例如如果数组有元素{5,2,1,4}
其中5是置换数组中的元素数。 和2是整数的长度,它将构成数组置换中的前2个元素前缀。 1,4是前缀整数,即5个元素排列组合中的长度2,因此缺少的元素是2,3,5其中1和4是所有排列的公共前缀,如下所示
[14235] [14253] [14325] [14352] [14523] [14532]其中输入数组是{5,2,1,4}
怎么做到这一点?

我有以下代码来获取一个缺失元素2,3和amp;的排列。 5但我没有得到如何编程整个解决方案

      static void Main(string[] args)
    {
       int output;
        int ip1;
        ip1 = Convert.ToInt32(Console.ReadLine());
        int ip2_size = 0;
        ip2_size = Convert.ToInt32(Console.ReadLine());
        int[] ip2 = new int[ip2_size];
        int ip2_item;
        for (int ip2_i = 0; ip2_i < ip2_size; ip2_i++)
        {
            ip2_item = Convert.ToInt32(Console.ReadLine());
            ip2[ip2_i] = ip2_item;
        }
        output = correctResult(ip1, ip2);
        Console.WriteLine(output);


    }

      static int correctResult(int n, int[] arr)
      {
        int permLength = 0;
        int prefLength = 0;
        int result = 0;
        permLength = n;
        prefLength = arr.Length;
        int[] permArray = new int[permLength];
        int len = 0;

        var missingNum = Enumerable.Range(1, 
         permLength).Except(arr).ToArray<int>();
        if (permLength < (missingNum.Length + len))
        {
            result = -1;
        }
        else
        {
            for (int i = 0; i < missingNum.Length; i++)
            {
                permArray[prefLength + i] = missingNum[i];
            }
            result = permute(missingNum, 0, missingNum.Length - 1);
        }

        return result;



    }


     static int permute(int[] arry, int i, int n)
        {
            int j;
            if (i == n)
            {
                int s1, s2;
                s1 = s2 = 0;
                for (int a = 0; a < n - 1; a++)
                {
                    for (int b = a + 1; b < n; b++)
                    {
                        if (arry[a] > arry[b])
                        {
                            s1++;
                        }

                    }
                    s2 = s2 + Math.Max(0, a + 1 - arry[a]);
                }
                int count = 0;
                if (s1 == s2)
                    count++;



                return count;


            }
            else
            {
                int count = 0;
                for (j = i; j <= n; j++)
                {
                    swap(ref arry[i], ref arry[j]);
                    count += permute(arry, i + 1, n);
                    swap(ref arry[i], ref arry[j]);
                }
                return count;
            }



        }

        static void swap(ref int a, ref int b)
        {
            int tmp;
            tmp = a;
            a = b;
            b = tmp;
        }         

2 个答案:

答案 0 :(得分:1)

尝试使用不可变类型解决此问题,更容易推理它们。如果在解决问题之后,您有一个尚未达到的性能目标,那么您可以开始尝试优化代码。

考虑以下方法,使用不可变堆栈跟踪当前排列:

static IEnumerable<IEnumerable<int>> GetPermutations(IList<int> input)
{
    if (input == null)
        throw new ArgumentNullException(nameof(input));

    if (input.Count < 2)
        throw new ArgumentException("Input does not have a valid format.");

    var setSize = input[0];
    var prefixSize = input[1];

    if (prefixSize != input.Count - 2)
        throw new ArgumentException("Input does not have a valid format.");

    if (input.Skip(2).Any(i => i > setSize)) //we are assuming, per example, that valid range starts at 1.
        throw new ArgumentException("Input does not have a valid format.");

    //Ok, we've got a valid input, interesting stuff starts here.
    var prefix = input.Skip(2).ToArray();
    var initialSet = Enumerable.Range(1, setSize)
                               .Except(prefix)
                               .ToArray();

    foreach (var p in getPermutations(ImmutableStack<int>.Empty, initialSet))
    {
        yield return prefix.Concat(p);
    }

    IEnumerable<IEnumerable<int>> getPermutations(ImmutableStack<int> permutation, IEnumerable<int> set)
    {
        if (permutation.Count == setSize - prefixSize)
        {
            yield return permutation;
        }
        else
        {
            foreach (var i in set)
            {
                foreach (var p in getPermutations(permutation.Push(i), set.Except(new[] { i })))
                {
                    yield return p;
                }
            }
        }
    }
}

就是这样,解决你的问题大约是10到12行实际代码(不考虑输入验证)。请注意,我在这里使用了一些c#7功能,但它很容易翻译成以前版本的语言。另外,我想强调我们正在进行的论证验证;在尝试任何事情之前确保你有一个有效的输入。

对于ImmutableStack<T>,您可以使用System.Collections.Immutable中的那个(您必须下载NuGet包)或实现自己的,简单:

private class ImmutableStack<T>: IEnumerable<T>
{
    public static readonly ImmutableStack<T> Empty = new ImmutableStack<T>();
    private readonly T head;
    private readonly ImmutableStack<T> tail;

    private ImmutableStack() { }
    private ImmutableStack(T head, ImmutableStack<T> tail)
    {
        Debug.Assert(tail != null);
        this.head = head;
        this.tail = tail;
        Count = tail.Count + 1;
    }

    public int Count { get; }
    public T Peek() => 
        this != Empty ? head : throw new InvalidOperationException("Empty stack.");
    public ImmutableStack<T> Pop() =>
        this != Empty ? tail : throw new InvalidOperationException("Empty stack.");
    public ImmutableStack<T> Push(T item) => new ImmutableStack<T>(item, this);

    public IEnumerator<T> GetEnumerator()
    {
        var current = this;

        while (current != Empty)
        {
            yield return current.head;
            current = current.tail;
        }
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

如果您使用System.Collections.Immutable中的集合,那么您可能希望为initalSetset使用某种不可变集。

答案 1 :(得分:0)

您可以重写permute方法(基于此answer):

private static IEnumerable<IEnumerable<T>> Permute<T>(List<T> prefix, List<T> suffix)
{
    for (var i = 0; i < suffix.Count; ++i)
    {
        var newPrefix = new List<T>(prefix) {suffix[i]};
        var newSuffix = new List<T>(suffix.Take(i).Concat(suffix.Skip(i + 1)));

        if (newSuffix.Count == 0)
        {
            yield return newPrefix;
            continue;
        }

        foreach (var permutation in Permute(newPrefix, newSuffix))
            yield return permutation;
    }
}

并像这样使用它:

public static void PrintAllPermutations()
{
    var input = new[] {5, 2, 1, 4};

    var prefix = input.Skip(2).Take(input[1]).ToList();
    var suffx = Enumerable.Range(1, input[0]).Except(prefix).ToList();

    foreach (var permutation in Permute(prefix, suffx))
        Console.WriteLine(string.Join(", ", permutation));
}

Reult会:

1, 4, 2, 3, 5
1, 4, 2, 5, 3
1, 4, 3, 2, 5
1, 4, 3, 5, 2
1, 4, 5, 2, 3
1, 4, 5, 3, 2