shi*_*zou 1 c++ arrays recursion
我正在尝试编写一个递归函数,检查两个数组是否具有相同的元素,即使它们没有排序,但是我不能更改数组,我无法复制它们或使用第三个/第四个数组而且它必须是递归的,最后,我无法更改函数的签名.
所以现在我必须摆脱overwrite(A2, len, i);因为那是在破坏A2,但是我没有看到任何方法去做它仍然有一个有效的功能......我可以提示如何做到这一点吗?也许有一种方法可以A2通过交换它们来保存元素,然后在递归结束时恢复它们?
简而言之,下面的算法对A2中A1的最后一个元素进行线性搜索,如果找到它,覆盖它并继续,这样就完成了,因此算法不会选择相同的元素两次,达到停止条件意味着所有元素因此它会返回true,否则将返回false.
bool foo(int A1[], int A2[], int len){//both arrays are size len
int i;
bool found = false;
if (len == 0)return true;//stopping condition for recursion
else{
for (i = 0; i < len && !found; i++)//linear search
if (A1[len - 1] == A2[i]){
overwrite(A2, len, i);//this function shifts back the whole array
found = true;
}
if (found == false) return false;
else foo(A1, A2, len - 1);
}
}
Run Code Online (Sandbox Code Playgroud)
样本i/o:
A1: 3 2 1
A2: 1 2 3
True
A1: 3 2 3
A2: 1 2 3
False
Run Code Online (Sandbox Code Playgroud)
解决方案可能是:
M,在A1它出现了多少次A2,包括计数M1小于MA1的所有值中的最大值以及A1中存在的次数A2,包括计数M2小于M1A1的所有值中的最大值以及A1中存在的次数A2,包括计数A1和A2为零或不同在代码中:
bool checkSame(int *A1, int *A2, int len) {
struct Same {
static bool check(int *A1, int *A2, int len, int limit) {
int index1=-1, count1=0;
for (int i=0; i<len; i++) {
if (A1[i] <= limit) {
if (index1==-1 || A1[i] > A1[index1]) {
index1 = i;
count1 = 1;
} else if (A1[i] == A1[index1]) {
count1++;
}
}
}
int index2=-1, count2=0;
for (int i=0; i<len; i++) {
if (A2[i] <= limit) {
if (index2==-1 || A2[i] > A2[index2]) {
index2 = i;
count2 = 1;
} else if (A2[i] == A2[index2]) {
count2++;
}
}
}
if (index1 == -1 && index2 == -1) return true;
if (count1 != count2 || count1 == 0 ||
A1[index1] != A2[index2]) return false;
return check(A1, A2, len, A1[index1]-1);
}
};
return Same::check(A1, A2, len, INT_MAX);
}
Run Code Online (Sandbox Code Playgroud)
该算法及时为O(n ^ 2)(最坏情况:数组相同且所有值都是唯一的)并且如果编译器支持尾调用优化则需要恒定空间.
以下是我的PC上0到3000个元素所需时间的图表.

请注意,然而这一切并不是解决问题的理想方案,而只是徒劳无功.一个真正的解决方案当然需要更多的上下文,因为有不同的最优性标准,但我可能会选择一个封闭的哈希表...在处理A1时添加元素并删除处理A2的元素(如果删除元素会在某些时候失败并且只有当数组不同时):
bool checkSame2(int *A1, int *A2, int len) {
std::vector<int> ht(len, -1), next(len, -1);
for (int i=0; i<len; i++) {
int k = (unsigned)A1[i]*69069 % len;
next[i] = ht[k]; ht[k] = i;
}
for (int i=0; i<len; i++) {
int k = (unsigned)A2[i]*69069 % len;
int prev=-1,p=ht[k];
while (p!=-1 && A1[p] != A2[i]) {
prev = p; p = next[p];
}
if (p == -1) return false;
if (prev == -1) ht[k] = next[p]; else next[prev] = next[p];
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
此解决方案的执行时间是紫色线在前一个图表中触及N轴(很难用这个比例来判断,但它是线性+噪声,如预期的那样).
出于好奇,我还尝试了什么是解决方案,如果"最佳"意味着只是让一些工作不那么可怕:
bool checkSame3(int *A1, int *A2, int len) {
std::map<int, int> counts;
for (int i=0; i<len; i++) counts[A1[i]]++;
for (int i=0; i<len; i++) {
if (--counts[A2[i]] < 0) return false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
毫无疑问,这比我手机上编写的手写代码哈希表版本快30-40倍(但当然仍然比递归版本快得多).