我需要获得许多可能的方法将数组划分为小的子数组。我们可以将数组分为verticaly和horizontaly。我的算法非常好,但时间复杂度太差了。你能看看如何改进吗?
参数
nStart
- 第一行子数组
nEnd
- 子阵列的最后一行
mStart
,mEnd
- 用于第二维(列)。
check()
- 检查结束条件的函数
return
- 分割数组的不同方法的数量。我们除了功能检查返回true
。
public static long divide(int nStart, int nEnd, int mStart, int mEnd) {
long result = 0;
for(int i = 1; i < nEnd - nStart; i++) {
if(check(nStart, nStart + i, mStart, mEnd) && check(nStart + i, nEnd, mStart, mEnd))
result += divide(nStart, nStart + i, mStart, mEnd) * divide(nStart + i, nEnd, mStart, mEnd);
}
for(int i = 1; i < mEnd - mStart; i++) {
if(check(nStart, nEnd, mStart, mStart + i) && check(nStart, nEnd, mStart + i, mEnd))
result += divide(nStart, nEnd, mStart, mStart + i) * divide(nStart, nEnd, mStart + i, mEnd);
}
return (result == 0 ? 1 : result) % 1000000000;
}
示例
输入
2 2
10
01
输出 2
输入
3 2
101
010
输出 5
我认为你需要知道check()
函数是如何工作的。当下一个子阵列只有一个或只有零时,我们停止分裂。这是代码:
public static boolean check(int nStart, int nEnd, int mStart, int mEnd) {
if((nEnd - nStart) + (mEnd - mStart) == 2)
return false;
for(int i = mStart; i < mEnd; i++) {
for(int j = nStart; j < nEnd; j++) {
if(bar[i][j] != bar[mStart][nStart])
return true;
}
}
return false;
}
答案 0 :(得分:1)
通过查看代码,我可以看到在递归的每个步骤中,您将二维数组划分为两个数组,其中包含一个水平或垂直切割。然后验证这两个部分是否满足check-method定义的某些条件,如果是,则将这两部分放入递归中。当递归不能再继续时,你返回1.下面我假设你的算法总是产生你想要的结果。
我担心这种算法的有效优化很大程度上取决于检查条件的作用。在琐碎的情况下,当问题崩溃成一个直截了当的数学问题时,它总是会返回真实的,这个问题可能具有一般的非递归解决方案。稍微复杂但仍然有效地可解决的情况是条件仅检查阵列的形状,这意味着例如check(1,5,1,4)将返回与check(3,7,5,8)相同的结果。
最复杂的当然是一般解决方案,其中检查条件可以是任何东西。在这种情况下,没有太多可以做的来优化您的暴力解决方案,但我想到的一件事是为您添加一个内存算法。您可以使用java.awt.Rectangle类(或创建自己的类)来保存子数组的维度,然后使用java.util.HashMap存储divide-method执行结果for furure参考,如果使用相同的参数再次调用该方法。这样可以防止可能发生的重复工作。
因此,您将haspmap定义为您类中的静态变量:
static HashMap<Rectangle,Long> map = new HashMap<Rectangle,Long>();
然后在除法方法的开头添加以下代码:
Rectangle r = new Rectangle(nStart,mStart,nEnd,mEnd);
Long storedRes = map.get(r);
if (storedRes != null) {
return storedRes;
}
然后将方法的结尾更改为表单:
result = (result == 0 ? 1 : result) % 1000000000;
map.put(r, result);
return result;
这可以为您的算法带来性能提升。
要回到我之前的判断,如果检查条件足够简单,则可以更有效地完成相同的优化。例如,如果你的检查条件只检查数组的形状,你只需要将它的宽度和高度作为地图的一个关键,这将减少地图的大小,并减少其中的正数命中数。