查找int []中的所有连续数字

时间:2010-11-25 20:19:33

标签: c# .net c#-4.0

我想在0到31的偶然数字的有序int [8]中找到所有连续数字。连续数字必须是最小长度3和最多5个数字。

在示例中,最后一个给我一个非常现实的问题。

例如:

int[] = new int[] { 3,7,14,16,23, 28, 29 ,30 } // no  result (28,29 is length of 2 numbers)

int[] = new int[] { 4,5,6,7,18, 19, 20 ,21 }  // 4,5,6,7 (yes! length of 4!!)

int[] = new int[] { 2.3.4.5.6.7.8.9 } // two results : 2,3,4 and 5,6,7,8,9  

我不想解决方案,而只是一个如何处理问题的例子,因为我正在尝试使用将军而且我真的被卡住了!

非常感谢您的帮助!

基督教

- 这是我开始的代码(不是我厨房的汤)

public partial class Test2 : Form
{
    public Test2()
    {
        InitializeComponent();
    }

    private void Test2_Load(object sender, EventArgs e)
    {          

         int[] numbers = new[] { 21, 4, 5, 22, 17, 6, 20, 23 };

      //  int[] numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8 };

        foreach (Campo r in FindRanges(numbers, 3))
        {
            listBox1.Items.Add(string.Join(", ", r.Select(x => x.ToString()).ToArray()));
        }



    }


    struct Campo : IEnumerable<int>
    {
        readonly int _start;
        readonly int _count;

        public Campo(int start, int count)
        {
            _start = start;
            _count = count;
        }

        public int Start
        {
            get { return _start; }
        }

        public int Count
        {
            get { return _count; }
        }

        public int End
        {
            get { return _start + _count - 1; }

        }

        public IEnumerator<int> GetEnumerator()
        {
            for (int i = 0; i < _count; ++i)
            {
                yield return _start + i;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {

            return this.GetEnumerator();

        }


        public static Campo operator +(Campo x, int y)
        {
            return new Campo(x.Start, x.Count + y);
        }

        public Campo removefirst()
        {
            return new Campo(this.Start + 3, this.Count);
        }

        public Campo removelast()
        {
            return new Campo(this.Start, this.Count - 1);
        }
    }

    static IEnumerable<Campo> FindRanges(IEnumerable<int> source, int minCount)
    {


        var ordered = source.OrderBy(x => x);

        Campo r = default(Campo);

        foreach (int value in ordered)
        {

            if (r.Count == 0)
            {
                r = new Campo(value, 1);
                continue;
            }


            if (r.Count == 5)
            {
                r = r.removefirst();

                continue;
            }

            if (value == r.End)
            {
               continue;
            }


            if ((value == 0 || value == 8 || value == 16 || value == 24) && (r.Count > minCount))
            {
                continue;
            }

            if ((value == 7 || value == 15 || value == 23 || value == 31) && (r.Count == 1))
            {
                continue;
            }

            else if (value == r.End + 1)
            {
               r += 1;
            }
            else
            {

                if (r.Count >= minCount)
                {
                    yield return r;
                }


                r = new Campo(value, 1);
            }
        }


        if (r.Count >= minCount)
        {
            yield return r;
        }
    }

}

5 个答案:

答案 0 :(得分:6)

我建议你举一些例子并将它们写在纸上。当您尝试手动解决问题时,请仔细研究您的直观行为 - 并将其转换为代码。

您可能想要计算您已在序列中找到的值的数量,以及之前的值是什么......

答案 1 :(得分:1)

伪代码:

按升序对数组进行排序 2 -

int count = 0
for i = 0 to array.length - 2
    if  {array[i + 1] - array[i] = 1 then
        count+=1
    else count=0}
    if { count >= 3 and count <= 5 then found}

答案 2 :(得分:1)

当然,这取决于你的问题总是局限于那些约束,我的意思是int [8]数组,0-31和3-5,但如果不是,我想你的问题无法解决通过一个天真的算法。

我的意思是,假设我们有这个数组:

int[] = new int[] { 2,3,4,5,6,7,8,9,10,11,12 };

和您的子集约束,即“连续数字集必须是最小长度3和最多5个数字”

从第一个元素到最后一个元素开始并填充最大可能连续子集的朴素算法将产生这两个子集:

[2,3,4,5,6] [7,8,9,10,11]

在这个解决方案中,12没有分区,但显然还有另一个可行的解决方案(实际上不止一个)包含所有数字,例如:

[2,3,4,5] [6,7,8,9] [10,11,12]

因此,您可以有多种可能性:

  1. 第一种解决方案没问题,您不需要尽可能多地覆盖已发现的连续集
  2. 第二种解决方案没问题,你需要尽可能多地覆盖已发现的连续集
  3. 第二种解决方案没问题,您需要尽可能多地覆盖已发现的连续集,并且可能包含尽可能少的子集数
  4. 在第一种情况下,你可以像其他回答者所指出的那样(嘿,男人,Jon Skeet回答你!:P)。
    相反,在第二和第三种情况下,它更复杂,因为它是Knapsack type problem,即NP完全问题,(特别是第三种情况听起来像Change-making problem)。

    这是我的两分钱,很明显,我再说一遍,如果你总是有相同的数组大小,范围和子集限制,问题就不存在了......

答案 3 :(得分:1)

对于迟到的更新感到抱歉,但时间非常压迫......

这是我的最终解决方案,对于serier有所有必要的限制(根据我的需要)。 谢谢大家

static IEnumerable<IEnumerable<int>> Sequences(IEnumerable<int> input, bool ascen = false, int min = 3)
    {
        int ord = ascen == false ? -1 : 1;

        input = ord == -1 ? input.OrderByDescending(x => x) : input.OrderBy(x => x);

        var seq = new List<List<int>>();
        foreach (var i in input)
        {
            var existing = seq.FirstOrDefault(lst => lst.Last() + ord == i);
            if ((existing == null) || (seq.Last().Count == 5) || i == 7 || i == 15 || i == 23)

                seq.Add(new List<int> { i });
            else
                existing.Add(i);
        }
        return min <= 1 ? seq : seq.Where(lst => lst.Count >= min);
    }

答案 4 :(得分:0)

1)在连续数字列表中拆分给定数组(你说数组已经是订单)

2)当添加到列表时,如果列表已经有5个元素添加到新列表

3)计数列表&gt; 2是你的结果