给定一个或多个长度相等的整数数组的集合,我希望预测最有可能的下一个数组。元素通常只增加1或跳回零,但其他变化肯定是可能的。
示例1:
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
I'd expect to get:
[0, 0, 3]
示例2:
[2, 0, 0]
[4, 1, 0]
[6, 2, 0]
I'd expect to get:
[8, 3, 0]
示例3:
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
I'd expect to get:
[0, 2, 0]
案例1和案例2很容易发现,但我很难弄清楚如何检测示例3中的模式。我需要哪些关键字来谷歌才能取得进展?< / p>
编辑:对保罗的回应。 尽管模式中的每个元素看起来都像任何东西,但如果模式不是以某种方式从不断添加和循环重置为零而构建,则模式已经非常无意义,以至于我的算法不再需要做得更好。所以我不关心复杂的多项式或[+ 1,+ 1,+ 2,-5,+ 7]加法规则。
答案 0 :(得分:1)
所以,如果我做对了,在给定的输入中你有
我想将两者中的任何一个或其中三个组合在一起是不错的(如例3中,第2列是常数和常数相加的组合)。
首先,我们必须考虑到,对于任何给定的输入,我们必须考虑到所有情况都可能发生在一列。您可以使用不同的变量为任何这些情况,结构,甚至没有任何变量创建对象。
其次,您必须检查每一列。因此,虽然未完全检查该列,但我们会查找多个内容:
是否有一个常数? (两个连续的行具有相同的数字)。如果它是真的,我们在变量中记住常量和最后一行。
两个连续数字之间有区别吗?如果是,那么我们有不断的加法,我们在变量中记住它在加法中使用的常数和加法发生的位置。注意!我们必须记住,添加可以在3个常数之后发生。因此,如果我们有一个常数和恒定的加法,我们必须看到常数停止的位置,以便我们可以在加法后继续它。
有没有循环?第一个数字是否等于同一列中的任何其他数字,但是其他任何行?如果发生这种情况,我们只需记住循环开始后添加多少(AND / OR常数)。这是最棘手的一个:我们可以有常数,恒定加法和循环。但它也不难,因为以前我们有恒定数量和不断增加。所以,一个循环只是那两个重复的循环。
这是使用您提供给我们的信息查找简单模式的算法。我希望它有用。
答案 1 :(得分:0)
使用格鲁吉亚的基本想法,我放弃了试图在20行或更少的时间内完成这项工作。下面的代码肯定没有检测到所有模式,但它对我的目的来说已经足够了。
虽然它无法检测到二阶模式,例如: 0,1,1,2,2,2,3,3,3,3,4,4,4,4,4,...
/// <summary>
/// Create a difference array. This array contains all the values that need to be added to
/// the elements in the original array in order to yield the next element.
/// The difference array will be one element shorter.
/// </summary>
/// <param name="array">Array to operate on.</param>
/// <returns>Difference array.</returns>
public static int[] ToDifferenceArray(this int[] array)
{
if (array == null || array.Length == 0)
throw new ArgumentNullException("array");
if (array.Length == 1)
return new int[0];
int[] div = new int[array.Length - 1];
for (int i = 0; i < array.Length - 1; i++)
div[i] = array[i + 1] - array[i];
return div;
}
/// <summary>
/// Determine whether an array of integers contains repeating elements.
/// the last iteration of the cycle may be incomplete.
/// </summary>
/// <param name="array">Array to examine.</param>
/// <returns>Length of cycle or 0 if no cycle could be found.</returns>
public static int FindCycle(this int[] array)
{
return FindCycle(array, 0);
}
/// <summary>
/// Determine whether an array of integers contains repeating elements.
/// the last iteration of the cycle may be incomplete.
/// </summary>
/// <param name="array">Array to examine.</param>
/// <param name="start">Index for cycle search.</param>
/// <returns>Length of cycle or 0 if no cycle could be found.</returns>
public static int FindCycle(this int[] array, int start)
{
if (array == null || array.Length == 0)
throw new ArgumentNullException("array");
if (start < 0)
throw new IndexOutOfRangeException("Search start may not be a negative number.");
if (start >= array.Length)
throw new IndexOutOfRangeException("Search start may not be larger than or equal to the length of the array.");
int index0 = start;
int index1 = index0;
while (true)
{
// Find next occurrence of pattern start value.
index1 = array.FirstIndexOf(array[index0], index1 + 1);
if (index1 < 0)
return 0;
// Length of potential cycle.
int length = (index1 - index0);
// Test each remaining element of the array to see
// whether it indeed repeats at regular intervals.
bool validCycle = true;
for (int i = index1 + 1; i < array.Length; i++)
if (array[i] != array[i - length])
{
validCycle = false;
break;
}
if (validCycle)
return length;
}
}
/// <summary>
/// Attempt to continue an array of integers.
/// </summary>
/// <param name="array">Sequence to extend.</param>
/// <returns>Best guess for next number in sequence.</returns>
public static int ExtendSequence(this int[] array)
{
// Handle special cases.
// Empty pattern.
if (array == null || array.Length == 0)
return 0;
// Pattern containing one element.
if (array.Length == 1)
return array[0];
// Pattern containing only identical elements (very common case).
bool constantPattern = true;
for (int i = 1; i < array.Length; i++)
if (array[0] != array[i])
{
constantPattern = false;
break;
}
if (constantPattern)
return array[0];
// Pattern containing only constantly incrementing elements (very common case).
constantPattern = true;
int dx = array[1] - array[0];
for (int i = 2; i < array.Length; i++)
if ((array[i] - array[i - 1]) != dx)
{
constantPattern = false;
break;
}
if (constantPattern)
return array[array.Length - 1] + dx;
// We have a complicated pattern.
// Try and find a cyclical repeat of pattern elements.
// At this time we always insist the pattern must start at the beginning of the array.
int patternLength = FindCycle(array);
if (patternLength > 0)
{
int repeats = array.Length / patternLength;
int offset = array.Length - (repeats * patternLength);
return array[offset];
}
// If there is no cyclical repeat of pattern elements,
// there may still be a cyclical repeat of element increments.
int[] increments = ToDifferenceArray(array);
patternLength = FindCycle(increments);
if (patternLength > 0)
{
int repeats = increments.Length / patternLength;
int offset = increments.Length - (repeats * patternLength);
return array[array.Length - 1] + increments[offset];
}
// Being unable to find a pattern, let's just return the last element.
return array[array.Length - 1];
}