具有最多不同数字算法的子广场

时间:2012-06-02 14:16:20

标签: algorithm

我试图为下面的问题创建一个有效的算法,但我想我失败了。 我给了一个 n * n 的板,其中包含不同的数字和一个整数 k (k <= n)。我必须在电路板中找到一个正方形 k * k ,其中不同数字的数量最大。对于这些例子:

n = 4 k = 3
10 9 8 1
7 6 5 7
5 3 0 2
3 4 1 3

n = 4 k = 2
1 2 1 2
2 1 2 1
1 2 1 2
2 1 3 4

答案如下:

9 8 1
6 5 7
3 0 2

1 2
3 4

我对这个问题的解决方案(在C ++中)是基于选择左上角的第一个方形k * k,创建一个将数字(键)与其出现频率(值)相关联的地图。然后我通过删除地图中方块的第一列并添加下一列来进一步移动方块一列。当我到达右侧时,我向下移动一排并离开边界。然后向下一步,直到边界。等等,直到我到达终点。答案基于特定时刻地图的最大尺寸。 我认为这个解决方案很难发明(但可能仍然比蛮力更好),我感谢任何建议。这个问题可以某种方式简化为修改后的最大矩形问题吗? (http://www.drdobbs.com/database/184410529



根据Daniele的建议编辑(其他详细信息)

在开始时,我的算法分析第一个k * k平方,即: 10 9 8 | 7 6 5 | 5 3 0。 在分析每个元素时,它会将正确的数据写入地图。所以起初我有一对(10 - > 1)(数字10出现一次),然后我添加(9 - > 1),(8 - &gt; 1),(7 - &gt; 1),(6 - &gt; 1),(5 - > 1)。然后我遇到了下一个5,所以我把它的出现改为2(5 - > 2)。最后我添加(3 - > 1),(0 - > 1)。实际上我的地图包含8个元素(因为如上所述,5个元素发生了两次)。我记得这个方形坐标和地图的大小。我向右移动了我的k * k方块一列。因此,我减少了地图中第一列的元素外观。因此,我删除对(10 - > 1)和(7 - > 1)并将(5 - &gt; 2)改为(5 - &gt; 1)。我添加了最后一列:(1 - &gt; 1),(7 - &gt; 1)和(2 - &gt; 1)(因为所有数字都是新的)。现在我注意到地图的大小比以前大(9> 8),所以我将当前坐标保存在旧坐标上。实际上我在这里结束我的算法(我的附加条件:if(map.size()== k * k)结束;)否则我会“走”一行低,而不是向左直到边界,那样我会已经完成了对所有可能的k * k平方的分析。

实际上我正在寻找一种更好的时间消耗解决方案,因为我的解决方案被测试系统拒绝(我超过了时间限制)。我认为它比蛮力更好,因为我不是逐个分析每个方格,但我可能是错的。无论如何,它仍然不够好。

我可以附加C ++代码,以防您更容易,但我怀疑它会有所帮助。我只是在寻找算法建议。

1 个答案:

答案 0 :(得分:1)

你的算法听起来很不错,O(n * n * k * log k)时间复杂度和O(k * k)内存。如果您知道值是小整数,则可以通过将数组替换为数组来摆脱log k。否则,实现算法的代码可能效率低下。尝试在nk变化时为代码计时,看看时间是否按预期增长。

作为另一个可能的方向,您可以尝试动态编程风格的解决方案。定义函数f(x, y, a, b)以计算锚定在a的{​​{1}} x b矩形中的唯一值集(可能是位图)。然后问题是找到(x, y)的最大值。 |f(x, y, k, k)|计算为4个或更多较小矩形集的并集,其大小为f(x, y, a, b) x a/2维度。如果缓存较小的矩形集,则不必重新计算它们。缓存会占用大量内存,但您可以通过安排分解来使用2个大小的功率来限制它。例如,

b/2

我认为这种方法更像是O(n * n * log k * log k),因此只会为 f(x, y, 21, 21) = f(x, y, 16, 16) union f(x + 16, y, 4, 16) union f(x + 20, y, 1, 16) union f(x, y + 16, 16, 4) union f(x, y + 20, 16, 1) union f(x + 16, y + 16, 4, 4) union f(x + 20, y + 16, 1, 4) union f(x + 16, y + 20, 4, 1) union f(x + 20, y + 20, 1, 1) 的大值付出代价,例如大于1000。