按元素(数组的子数组中的元素)降序对序列(数组中的子数组)进行排序

Sort a sequence (a sub-array in a array) in decreasing order by their elements (elements in the sub-array of an array)

几天来我一直在尝试使用 C# 找到解决此问题的方法。我能够按长度对它们进行排序,但我无法找出从最左边到最右边对数组进行排序的解决方案。

他们给出的提示是定义一个class序列来保存元素序列。我们将实现 IComparable<Sequence> 以递减顺序按长度比较序列(当长度相同时按递减顺序排列元素)。稍后我们将使用我们的 TreeMultiSet class。在内部,我们将保留 S 的前 10 个子序列,即 P 的幸运子序列的多集,按长度降序排列(当长度相同时,按内容降序排列)。当我们在多集中有 10 个子序列并且我们添加第 11 个序列时,它会在顺序中占据正确的位置,因为 IComparable<Sequence> 定义。之后我们可以删除第 11 个子序列,因为它不在前 10

这是问题所在:

给定一个包含 L 个整数 L(1 < L < 50,000)和一个数字 N 的序列 P。我们称 P 中整数的每个子序列为“幸运子序列”,其总和等于 N . 假设我们有一个序列 S,包含 P 的所有幸运子序列,并按长度降序排列。当长度相同时,序列按其元素降序排列:从最左边到最右边。编写一个程序来 return S

的前 10 个元素

示例:给定 N = 5 和序列 P = {1, 1, 2, 1, -1, 2, 3, -1, 1, 2, 3, 5, 1, -1, 2, 3}。序列S由P的以下13个子序列组成:

[1, -1, 2, 3, -1, 1] 
[1, 2, 1, -1, 2]
[3, -1, 1, 2]
[2, 3, -1, 1]
[1, 1, 2, 1]
[1, -1, 2, 3]
[1, -1, 2, 3]
[-1, 1, 2, 3]
[5, 1, -1]
[2, 3]
[2, 3] 
[2, 3]
[5]

我的解决方案:

其实看提示的时候没看懂所以想了个办法

class Find
    {
        //Function to manually create an array with N elements
        public static int[] ArrCreate(int n, int[] Arr)
        {
            for (int i = 0; i < n; i++)
            {
                Arr[i] = Convert.ToInt32(Console.ReadLine());
            }
            return Arr;
        }
        //Create a Dictionary class type to hold sub-array with sum of sub-array equal to given number k
        public static Dictionary<int, ArrayList> SubSeqEqual2N()
        {
            Console.WriteLine("Input k: ");
            int k = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("Input n element to create an Array: ");
            int n = Convert.ToInt32(Console.ReadLine());
            int[] Arr = new int[n];
            int[] newArr = ArrCreate(n, Arr);
            int keyIndex = 0;
            //ArrayList arlist = new ArrayList();
            Dictionary<int, ArrayList> SeqofLuckyArr = new Dictionary<int, ArrayList> { };
            //Create a loop to find sub-array with the sum equal to given number K.
            for (int i = 0; i < newArr.Length; i++)
            {
                int sum = 0;
                for (int j = i; j < newArr.Length; j++)
                {
                    sum = sum + newArr[j];
                    if (sum == k)
                    { 
                        //When sub-array with the sum equal to given number K is found then add them into a temp Arraylist, also increment the keyIndex.
                        keyIndex++;
                        ArrayList temp = new ArrayList();
                        for (int ko = i; ko <= j; ko++)
                        {
                            temp.Add(newArr[ko]);
                        }
                        //DEBUG PURPOSE
                        /*Console.Write("{");
                        foreach (var hehe in temp)
                        {
                            
                            Console.Write("{0}", string.Join(", ", hehe));
                            
                        }
                        Console.Write("}");
                        Console.WriteLine("");
                        arlist.AddRange(temp);*/
                        //Then add that temp array as value into a Dictionary <key,value>type with that KeyIndex.
                        SeqofLuckyArr.Add(keyIndex,temp);
                    }
                }
            }
            //DEBUG PURPOSE
            //My method to sort the sub-array in the Dictionary by sub-array length and by key index.
            foreach(KeyValuePair<int,ArrayList> kvp in SeqofLuckyArr.OrderByDescending(x => x.Value.Count).ThenBy(y => y.Key))
            {
                Console.Write("Key={0} ",kvp.Key);
                Console.Write(",");
                Console.Write("Value={ ");
                foreach (var hoho in kvp.Value)
                {
                    Console.Write("{0} ", string.Join(", ", hoho));
                }
                Console.WriteLine("}");
                Console.WriteLine("");
                arlist.AddRange(kvp.Value);
            }
            //DEBUG PURPOSE
            return SeqofLuckyArr;
        }
    }

我尝试先找到和等于给定数字K的子数组,然后将它们作为值添加到字典中,其键作为索引。然后使用 OrderByDecreasing 方法按长度对子数组进行排序。

结果:

Key=4 ,Value={ 1 -1 2 3 -1 1 }

Key=2 ,Value={ 1 2 1 -1 2 }

Key=1 ,Value={ 1 1 2 1 }

Key=3 ,Value={ 1 -1 2 3 }

Key=6 ,Value={ 2 3 -1 1 }

Key=7 ,Value={ 3 -1 1 2 }

Key=8 ,Value={ -1 1 2 3 }

Key=12 ,Value={ 1 -1 2 3 }

Key=11 ,Value={ 5 1 -1 }

Key=5 ,Value={ 2 3 }

Key=9 ,Value={ 2 3 }

Key=13 ,Value={ 2 3 }

Key=10 ,Value={ 5 }

但是结果和例子不一样。我的问题是我卡在“当长度相同时,序列按其元素降序排列:从最左边到最右边”。正如我所想的从最左到最右是子数组的关键索引从低到高。

谁能帮我找到按元素降序排列子数组的合适方法?如果我的版本也不适合在SO上提问我会删除我的问题。

谢谢!

看来问题只出在您的订单上。序列的内容与示例相同。

首先,您订购的线路不完全符合指定的规则:

foreach(KeyValuePair<int,ArrayList> kvp in SeqofLuckyArr
                                           .OrderByDescending(x => x.Value.Count)
                                           .ThenBy(y => y.Key))

[...] kept in decreasing order by their length. When the length is the same, the sequences are ordered in decreasing order by their elements: [...]

第一个顺序似乎是正确的 (OrderByDescending(x => x.Value.Count)),按序列长度的降序排列。第二次排序目前按序列的“关键索引” 升序排列。根据“幸运子序列”的内容,这应该是 descending/decreasing (ThenByDescending) 顺序。

解决所有这些问题的一种方法是引入一个 IComparer 实现,该实现有点类似于给定的提示。下面的 IComparer 能够将两个序列 (int[]) 作为输入并判断两个序列中的哪一个应该出现在另一个序列之前(请参阅 the documentation 以了解 return IComparer.Compare 的值表示:

public class IntArrayComparer : IComparer<int[]>
{
    public int Compare(int[] x, int[] y)
    {
        // Ensure we don't get a null-ref exception further down
        if (x == null || y == null)
            // x should come before (-1) or after (1) y (default ascending order)
            return y == null ? -1 : 1;
        
        // If the lengths are different, the length is the first ordering priority
        if (x.Length != y.Length)
            // Use the built-in 'CompareTo' method for the 'int' type
            return x.Length.CompareTo(y.Length);
        
        // Lengths are the same, so we compare the contents
        for (var i = 0; i < x.Length; i++)
        {
            var comparison = x[i].CompareTo(y[i]);
            // If the elements in the two seq. are different, we return the ordering
            if (comparison != 0)
                return comparison;
        }
        return 0;
    }
}

现在前面提到的你的订单行变得更简单了(主观意见:)):

foreach(KeyValuePair<int,ArrayList> kvp in SeqofLuckyArr
                                           .OrderByDescending(x => x.Value, new IntArrayComparer()))

查看 this fiddle 以测试 运行 订购部分。

提示:实际上您甚至不需要将子序列存储在 Dictionary 中 - List 就足够了。

抱歉回复晚了。在参考上面的 Imcomparer 实现之后。我能够获得与示例相同的输出。这是我的代码,供遇到与我相同问题的任何人使用。

class Find
    {
        public static int[] ArrCreate(int n, int[] Arr)
        {
            for (int i = 0; i < n; i++)
            {
                Arr[i] = Convert.ToInt32(Console.ReadLine());
            }
            return Arr;
        }
        public static void SubSeqEqual2N()
        {
            Console.WriteLine("Input k: ");
            int k = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("Input n element to create an Array: ");
            int n = Convert.ToInt32(Console.ReadLine());
            int[] Arr = new int[n];
            int[] newArr = ArrCreate(n, Arr);
            //int keyIndex = 0;
            //ArrayList arlist = new ArrayList();
            //Dictionary<int, ArrayList> SeqofLuckyArr = new Dictionary<int, ArrayList> { };
            
            //Create a List of int array to store 
            List<int[]> luckyArray = new List<int[]>{ };
            for (int i = 0; i < newArr.Length; i++)
            {
                int sum = 0;
                for (int j = i; j < newArr.Length; j++)
                {
                    sum = sum + newArr[j];
                    if (sum == k)
                    {
                        //keyIndex++;
                        ArrayList temp = new ArrayList();
                        for (int ko = i; ko <= j; ko++)
                        {
                            temp.Add(newArr[ko]);
                        }

                        //Convert ArrayList temp into int array for applying IComparer.Compare<Int[],Int[]>
                        int[] luckySubArray = temp.ToArray(typeof(int)) as int[];
                        luckyArray.Add(luckySubArray);

                        //SeqofLuckyArr.Add(keyIndex,temp);
                    }
                }
            }
            var orderedSeq = luckyArray.OrderByDescending(s => s, new IntArrayComparer());           
            foreach(var seq in orderedSeq)
            {
                Console.Write("[ ");
                foreach (var i in seq)
                {
                    Console.Write("{0} ", string.Join(", ", i));
                }
                Console.Write(" ]");
                Console.WriteLine("");
            }

        }
    }
    public class IntArrayComparer : IComparer<int[]>
    {
        public int Compare(int[] x, int[] y)
        {
            // Ensure we don't get a null-ref exception further down
            if (x == null || y == null)
                // x should come before (-1) or after (1) y (default ascending order)
                return y == null ? -1 : 1;

            // If the lengths are different, the length is the first ordering priority
            if (x.Length != y.Length)
                // Use the built-in 'CompareTo' method for the 'int' type
                return x.Length.CompareTo(y.Length);

            // Lengths are the same, so we compare the contents
            for (var i = 0; i < x.Length; i++)
            {
                var comparison = x[i].CompareTo(y[i]);
                // If the elements in the two seq. are different, we return the ordering
                if (comparison != 0)
                    return comparison;
            }
            return 0;
        }
    }

并且输出:

[ 1 -1 2 3 -1 1  ]
[ 1 2 1 -1 2  ]
[ 3 -1 1 2  ]
[ 2 3 -1 1  ]
[ 1 1 2 1  ]
[ 1 -1 2 3  ]
[ 1 -1 2 3  ]
[ -1 1 2 3  ]
[ 5 1 -1  ]
[ 2 3  ]
[ 2 3  ]
[ 2 3  ]
[ 5  ]