在一周内查找连续天数的算法

时间:2012-01-13 15:40:24

标签: algorithm dayofweek weekday

用户可以从列表中选择任意数量的工作日。算法应找到所选天数的最长连续组。如果小组跨越两周,则开始日期可以在结束日之后。如果它更简单,则只需要检测至少3天的一组。越过周边界,这最多允许一组。 (一周内没有两组没有连接的3天。)

例如,如果用户从列表中选择星期一,星期二,星期三和星期六,则显示应为“星期一 - 星期三和星期六”。

另一个例子是:周三,周五,周六,周日,周一 - > “星期三,星期五,星期五”。

是否有一种有效的算法,最好用C#或类似的语言?我的C#hackwork现在已超过一页(包括几条评论),但仍未完成。

2 个答案:

答案 0 :(得分:2)

使用this answer,稍作修改:

使用dtb GroupAdjacentBy的修改版本,该版本接受minCount作为参数:

public static IEnumerable<IEnumerable<T>> GroupAdjacentBy<T>(
    this IEnumerable<T> source, Func<T, T, bool> predicate, int minCount)
{
    using (var e = source.GetEnumerator())
    {
        if (e.MoveNext())
        {
            var list = new List<T> { e.Current };
            var pred = e.Current;
            while (e.MoveNext())
            {
                // if adjacent, add to list
                if (predicate(pred, e.Current))
                {
                    list.Add(e.Current);
                }
                else
                {
                    // otherwise return previous elements:
                    // if less than minCount elements,
                    // return each element separately
                    if (list.Count < minCount)
                    {
                        foreach (var i in list)
                            yield return new List<T> { i };
                    }
                    else
                    {
                        // otherwise return entire group
                        yield return list;
                    }

                    // create next group
                    list = new List<T> { e.Current };
                }
                pred = e.Current;
            }
            yield return list;
        }
    }
}

并将GroupAdjacentBy的条件更改为按周转换分组:

// week starts with Monday, so this should
// represent: Wed, Fri, Sat, Sun, Mon
int[] array = new int[] { 1, 2, 4, 5, 6, 0 };

Func<int, int, bool> adjacentCriteria = (x, y) => (x+1==y) || (x==6 && y==0);

string result = string.Join(", ", array
    .GroupAdjacentBy(adjacentCriteria, 3)
    .Select(g => new int[] { g.First(), g.Last() }.Distinct())
    .Select(g => string.Join("-", g)));

Console.WriteLine(result); // output: 1, 2, 4-0

答案 1 :(得分:0)

我已经完成了我的版本。它比另一个稍长,但它再次处理文本表示并完成此任务。怎么样?

using System;
using System.Text;

namespace WeekMathTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] weekDayNames = new string[] {
                "Mon",
                "Tue",
                "Wed",
                "Thu",
                "Fri",
                "Sat",
                "Sun"
            };

            WeekDays weekDays = WeekDays.Monday | WeekDays.Tuesday | WeekDays.Thursday | WeekDays.Saturday | WeekDays.Sunday;

            Console.WriteLine(WeekDayGroup(weekDays, weekDayNames));
        }

        static string WeekDayGroup(WeekDays weekDays, string[] weekDayNames)
        {
            int groupStart = 0, groupEnd = 0, groupLength = 0;
            int maxGroupStart = 0, maxGroupEnd = 0, maxGroupLength = 0;

            // Iterate all days in a repeated range
            // (Sat/Sun doesn't need to be repeated or it would be in the first group)
            for (int day = 1; day <= 7 + 5; day++)
            {
                // Is this day set?
                int bitValue = 1 << ((day - 1) % 7);
                bool daySet = ((int) weekDays & bitValue) != 0;
                if (daySet)
                {
                    if (groupStart == 0)
                    {
                        // First day set, remember it as group start
                        groupStart = day;
                        groupEnd = day;
                        groupLength = 1;
                    }
                    else
                    {
                        // Group has already been started, set new end
                        groupEnd = day;
                        groupLength = groupEnd - groupStart + 1;
                        if (groupLength == 7)
                        {
                            // Seen every day of the week, stop here
                            break;
                        }
                    }
                }
                else
                {
                    if (groupLength >= 3 && groupLength > maxGroupLength)
                    {
                        // Group was long enough and longer than the last one, save it
                        maxGroupStart = groupStart;
                        maxGroupEnd = groupEnd;
                        maxGroupLength = groupLength;
                    }
                    // Reset operation variables
                    groupStart = 0;
                    groupEnd = 0;
                    groupLength = 0;
                }
            }
            // Final check
            if (groupLength >= 3 && groupLength > maxGroupLength)
            {
                // Group was long enough and longer than the last one, save it
                maxGroupStart = groupStart;
                maxGroupEnd = groupEnd;
                maxGroupLength = groupLength;
            }

            // Clear all group days from the original value
            for (int day = maxGroupStart; day <= maxGroupEnd; day++)
            {
                int bitValue = 1 << ((day - 1) % 7);
                weekDays = (WeekDays) ((int) weekDays & ~bitValue);
            }

            // Generate output string
            StringBuilder sb = new StringBuilder();
            for (int day = 1; day <= 7; day++)
            {
                int bitValue = 1 << ((day - 1) % 7);
                bool daySet = ((int) weekDays & bitValue) != 0;
                if (daySet)
                {
                    if (sb.Length > 0) sb.Append(", ");
                    sb.Append(weekDayNames[day - 1]);
                }
                else if (day == maxGroupStart)
                {
                    if (sb.Length > 0) sb.Append(", ");
                    sb.Append(weekDayNames[day - 1]);
                    sb.Append("-");
                    sb.Append(weekDayNames[(maxGroupEnd - 1) % 7]);
                }
            }
            return sb.ToString();
        }

        [Flags]
        enum WeekDays
        {
            Monday = 1,
            Tuesday = 2,
            Wednesday = 4,
            Thursday = 8,
            Friday = 16,
            Saturday = 32,
            Sunday = 64
        }
    }
}