下面的最优解作为O(n)的运行时间并且不仅计算是否有两个以上的连续序列,而且计算
您的问题的解决方案可以非常有效和简单地解决,无需使用任何类型的图论,而只需使用您对数组的了解,并利用您对它们在内存中的布局方式的了解。下面的 C 程序演示了这个原理。
static inline void TrackLength(int **hpnCountPtr, int *pSeqStart)
{
(*((*hpnCountPtr) ? (*hpnCountPtr) : (*hpnCountPtr = pSeqStart)))++;
}
static int FindSequences(char *pcbGrid, int nWidth, int nHeight)
{
int nColIndex, nRowIndex, nSeqTotal;
int *panResult, *pnHorzSeq, *panVTable;
int **panVertSeqs;
size_t nResultLen;
char *pcbCheckPtr;
nResultLen = (size_t) (2 * nWidth * nHeight) * sizeof(int);
panResult = (int*) memset(alloca(nResultLen), 0, nResultLen);
panVTable = panResult + (nWidth * nHeight);
panVertSeqs = (int**) alloca(nWidth * sizeof(int*));
for (nColIndex = 0; nColIndex < nWidth; panVertSeqs[nColIndex++] = (int*) NULL);
for (pcbCheckPtr = pcbGrid, nRowIndex = 0; nRowIndex < nHeight; nRowIndex++)
for (pnHorzSeq = (int*) NULL, nColIndex = 0; nColIndex < nWidth; nColIndex++, pcbCheckPtr++)
{
if (*pcbCheckPtr != 'X')
{
pnHorzSeq = panVertSeqs[nColIndex] = (int*) NULL;
continue;
}
TrackLength(&pnHorzSeq, panResult + (pcbCheckPtr - pcbGrid));
TrackLength(panVertSeqs + nColIndex, panVTable + (pcbCheckPtr - pcbGrid));
}
/* Insert Debug Information Here */
for (nSeqTotal = 0, nColIndex = nWidth * nHeight; nColIndex; nColIndex--)
if (*panResult++ > 1)
nSeqTotal++;
return nSeqTotal;
}
关键在于您要求只需要找到水平和垂直序列,而不是对角线。作为一个 2D 数组,这意味着可以通过知道 2D 数组是简单的平坦的、连续的内存块来实现巨大的优化,这些内存块可以一次从头到尾遍历。
利用内存排列,可以仅使用单个计数器跟踪水平序列,该计数器针对X 的每个连续内存位置递增,并在每次遇到非X 时重置为零。如果在数组的 2D 视图中的每个“行”的末尾强制重置计数器,这将成功跟踪水平序列。
在跟踪水平序列的同时,我们可以同时跟踪垂直序列。然而,由于数组中一列中的相邻单元格以width 字节的间距出现,我们必须保留一个width 计数器数组,它们在我们扫描行时跟踪一行中所有可能的垂直序列,每个序列一个序列列。
最后,我的解决方案的真正优点在于计数器实际上是指向两个二维数组的指针(一个用于跟踪垂直序列,一个用于跟踪水平序列)。每个数组中的每个位置都代表一个序列的潜在开始,当函数完成时,每个数组将在每个位置包含从该位置开始的每个序列的长度。
下图最好地说明了这一点:
Grid Horizontal Vertical
Sequences Sequences
....X...X. 0000100010 0000300030
.X..X...X. 0100100010 0300000000
.XXXX..XXX 0400000300 0011000201
.X.....X.. 0100000100 0000000000
水平序列数组中的每个数字表示从该点开始的水平序列的长度。垂直序列的 Vertical Sequences 数组也是如此。
由于程序使一个,并且恰好一个,传递输入数组,并且每个数组元素的处理时间是恒定的,因此该算法在 O(n) 中运行并且对于任何网格大小。
如果在下面的程序中插入以上函数:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloca.h>
#define GRID_WIDTH 18
#define GRID_HEIGHT 9
static char *s_szGrid =
"X X X X X X X X X "
" X X X X X X X X X"
"X X X X X X X X X "
" X X X X X X X X X"
"XXX X X X X X X X "
" X X X X X X X X X"
"XXXXX X X X X X X "
" X X X X X X X X X"
"X X XXX X X X X X ";
void main(void)
{
int nSeqTotal = FindSequences(s_szGrid, GRID_WIDTH, GRID_HEIGHT);
printf("\nGrid has %i contiguous sequences\n", nSeqTotal);
if (nSeqTotal)
printf(">>> %sone sequence detected\n", (nSeqTotal > 1) ? "more than " : "");
}
然后您将以下调试代码块插入到您看到/* Insert Debug Information Here */ 注释的函数中:
{
int nXIndex, nYIndex;
int *pnValue;
printf("Horizontal:\n");
for (pnValue = panResult, nYIndex = 0; nYIndex < nHeight; nYIndex++, printf("\n"))
for (nXIndex = 0; nXIndex < nWidth; nXIndex++, printf("%2i", *pnValue++));
printf("\nVertical:\n");
for (nYIndex = 0; nYIndex < nHeight; nYIndex++, printf("\n"))
for (nXIndex = 0; nXIndex < nWidth; nXIndex++, printf("%2i", *pnValue++));
}
然后程序会产生如下输出:
Horizontal:
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
3 0 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
5 0 0 0 0 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 3 0 0 0 1 0 1 0 1 0 1 0 1 0
Vertical:
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 5 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 0 0 3 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 0 0 0 0 2 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
Grid has 6 contiguous sequences
>>> more than one sequence detected
如果输入网格改为这个,但是:
static char *s_szGrid =
"X X X X X X X X X "
" X X X X X X X X X"
"X X X X X X X X X "
" X X X X X X X X X"
"X X X X X X X X X "
" X X X X X X X X X"
"X X X X X X X X X "
" X X X X X X X X "
"X X X X X X X X XX";
那么输出将是:
Horizontal:
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 0
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 2 0
Vertical:
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 0
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1
Grid has 1 contiguous sequences
>>> one sequence detected