给定两个大小为M和N的排序数组 . 我试图实现时间复杂度为O(logM logN)的算法 . 该策略基本上是根据长度条件比较两个子阵列的中间索引元素 .
// Test case 1
// Works for all position except when kth is 6
int[] num1 = {6,7,8,9,10,11,12};
int[] num2 = {1,2,3,4,5};
// Test case 2
// Always print the next smallest element
int[] num3 = {1,3,5,7,9};
int[] num4 = {2,4,6,8,10,12,14,16,18,20,22,24,30,40,50,56,77,35};
public static int findKth(int[] A, int p1, int r1, int[] B, int p2, int r2, int k){
if (p1 > r1) {
return B[p2+k-1];
} else if (p2 > r2) {
return A[p1+k-1];
}
int midA = p1 + (int)Math.floor((r1-p1)/2);// Middle element from subarray A
int midB = p2 + (int)Math.floor((r2-p2)/2);// Middle element from subarray B
/**
* Compare the sum of number of elements from left-subarray up to middle element.
*/
if ((midA-p1+midB-p2+2) < k) {
// We don't need to the left-subarray based on the comparisons between middle element
if (A[midA] > B[midB]) {
return findKth(A, p1, r1, B, midB+1, r2, k-(midB-p2+1)); //
} else {
return findKth(A, midA+1, r1, B, p2, r2, k-(midA-p1+1)); //
}
} else {
// We don't need to the right-subarray based on the comparisons between middle element.
if (A[midA] > B[midB]) {
return findKth(A, p1, midA-1, B, p2, r2, k);
} else {
return findKth(A, p1, r1, B, p2, midB-1, k);
}
}
}
我觉得我用的策略应该是正确的 . 但是对于上面显示的两个测试用例,它将在某个特定的第k个值中打印错误的输出 . 所以我猜我的策略一定有问题 . 任何人都可以简要描述这个实现的哪个部分不正确?谢谢!
3 回答
在StackOverflow上已经有很好的解决方案,例如here和here,所以我将专注于识别错误:
这一行:
应修改为使用
<=
:您可以通过以下小例子了解为什么需要这样做:
其他变量将是:
所以表达式
midA-p1+midB-p2+2
将是2
. 在这种情况下,你显然想要丢弃A的元素,而不是B的唯一元素 .请注意,通常可以包含执行
if
块的k情况,因为您永远不会丢弃k(即太多)元素:作为递归调用的最后一个参数传递的表达式总是最多K-1 .另一方面,当
if
表达式为k时,转到else
部分是错误的,因为midA或midB可能是该第k个元素的索引,并且它将被抛出 .如果我能在你的代码片段中找到错误,我会更新我的答案 . 现在你可以看看我的代码哪个逻辑与你的完全相同,除了:
简单和我的代码的小尺寸的主要区别是我避免了一些if-else条件(对于长度条件)通过在第一个数组/索引对不小的情况下调用交换其参数的函数 .
时间复杂度是
O(log(m + n))
.时间复杂度为O(log(min(m,n)))