给定两个大小为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个值打印错误的输出。所以我猜我的策略一定有问题。谁能简单描述一下这个实现的哪个部分不正确?谢谢!
答案 0 :(得分:2)
如果我能在您的代码段中找到错误,我会更新我的答案。现在你可以看看我的代码哪个逻辑与你的完全相同,除了:
该策略基本上是比较两个中间指数元素 基于长度条件的子阵列。
我的代码的简单性和小尺寸的主要区别是我通过在第一个数组/索引对不小的情况下调用交换其参数的函数来避免一些if-else条件(对于长度条件)。
<script>
var titleArray = ["TITLE-1","TITLE-2","TITLE-3","TITLE-4"];
var N = titleArray.length;
var i = 0;
setInterval(func,5000);
function func(){
if (i == 4) {
i = 0;
}
document.title = titleArray[i];
i++;
}
</script>
时间复杂度为public static int findKth(int[] A, int i, int[] B, int j, int k) {
// Here is the simple trick. We've just changed the parameter order if first array is not smaller.
// so that later we won't need to write if-else conditions to check smaller/greater stuff
if((A.length - i) > (B.length - j))
{
return findKth(B, j, A, i, k);
}
if(i >= A.length)
{
return B[j + k - 1];
}
if(k == 1)
{
return Math.min(A[i], B[j]);
}
int aMid = Math.min(k / 2, A.length - i);
int bMid = k - aMid;
if(A[i + aMid - 1] <= B[j + bMid - 1])
{
return findKth(A, i + aMid, B, j, k - aMid);
}
return findKth(A, i, B, j + bMid, k - bMid);
}
public static int findKthSmallestElement(int[] A, int[] B, int k)
{
if(k > A.length + B.length)
return -1;
return findKth(A, 0, B, 0, k);
}
。
答案 1 :(得分:0)
StackOverflow上已经有很好的解决方案,例如here和here,所以我将专注于识别错误:
这一行:
if ((midA-p1+midB-p2+2) < k) {
应修改为使用<=
:
if ((midA-p1+midB-p2+2) <= k) {
您可以通过以下小例子了解为什么需要这样做:
A = {1,3}
B = {2}
其他变量将是:
p1 = p2 = r2 = midA = midB = 0
r1 = 1
所以表达式midA-p1+midB-p2+2
将是2
。在这种情况下,你显然想要丢弃A的元素,而不是B的唯一元素。
请注意,通常可以包含 k 案例来执行if
块,因为你永远不会丢弃 k (即太多)元素:作为递归调用的最后一个参数传递的表达式总是最多 k-1 。
另一方面,当else
表达式 k 时转到if
部分是错误的,因为 midA 或 midB 可能是 k th 元素的索引, 将被抛出。
答案 2 :(得分:0)
#include <bits/stdc++.h>
using namespace std;
int findKthElement(int a[],int start1,int end1,int b[],int start2,int end2,int k){
if(start1 >= end1)return b[start2+k-1];
if(start2 >= end2)return a[start1+k-1];
if(k==1)return min(a[start1],b[start2]);
int aMax = INT_MAX;
int bMax = INT_MAX;
if(start1+k/2-1 < end1) aMax = a[start1 + k/2 - 1];
if(start2+k/2-1 < end2) bMax = b[start2 + k/2 - 1];
if(aMax > bMax){
return findKthElement(a,start1,end1,b,start2+k/2,end2,k-k/2);
}
else{
return findKthElement(a,start1 + k/2,end1,b,start2,end2,k-k/2);
}
}
int main(void){
int t;
scanf("%d",&t);
while(t--){
int n,m,k;
cout<<"Enter the size of 1st Array"<<endl;
cin>>n;
int arr[n];
cout<<"Enter the Element of 1st Array"<<endl;
for(int i = 0;i<n;i++){
cin>>arr[i];
}
cout<<"Enter the size of 2nd Array"<<endl;
cin>>m;
int arr1[m];
cout<<"Enter the Element of 2nd Array"<<endl;
for(int i = 0;i<m;i++){
cin>>arr1[i];
}
cout<<"Enter The Value of K";
cin>>k;
sort(arr,arr+n);
sort(arr1,arr1+m);
cout<<findKthElement(arr,0,n,arr1,0,m,k)<<endl;
}
return 0;
}
Time Complexcity是O(log(min(m,n)))