有没有办法忽略数组中的元素而不更改递归函数中的数组?

时间:2014-12-24 15:27:43

标签: 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);

    }
}

示例i / o:

A1:    3   2   1
A2:    1   2   3
True

A1:    3   2   3
A2:    1   2   3
False

3 个答案:

答案 0 :(得分:5)

解决方案可能是:

  1. 查找M中的最大值A1以及出现的次数
  2. 检查A2是否相同,包括计数
  3. 查找小于M1的所有值中的最大值M以及A1中存在的次数
  4. 检查A2是否相同,包括计数
  5. 查找小于M2的所有值中的最大值M1以及A1中存在的次数
  6. 检查A2是否相同,包括计数
  7. 重复此方式,直到A1A2的计数器为零或不同
  8. 代码:

    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);
    }
    

    该算法及时为O(n ^ 2)(最坏情况:数组相同且所有值都是唯一的),如果编译器支持尾调用优化,则需要恒定空间。

    以下是我的电脑上0到3000个元素所需时间的图表。

    enter image description here

    请注意,然而这一切并不是解决问题的理想方案,而只是徒劳无功。一个真正的解决方案当然需要更多的上下文,因为有不同的最优性标准,但我可能会选择一个封闭的哈希表...在处理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;
    }
    

    此解决方案的执行时间是紫色线在前一个图表中触及N轴(很难用这个比例判断,但是它的线性+噪音,如预期的那样)。

    出于好奇,我还尝试了什么是解决方案,如果&#34;最佳&#34;意味着只是让一些不起作用的东西:

    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;
    }
    

    ,毫不奇怪,这比我手机上的手动编码哈希表版本慢30-40倍(但当然仍然比递归版本快得多)。

答案 1 :(得分:1)

如果允许临时更改数组,只要在最后一次递归调用返回之前还原它们,就可以将A2中的匹配元素与索引处的元素交换在递归调用之前len - 1,然后将它们交换回来。由于递归调用只会查看索引范围0len - 2,因此不会考虑匹配元素。

答案 2 :(得分:1)

这是一个满足您所有要求的解决方案。它重新排列数组,然后重新排列它们。它使用递归,不使用其他数组,也不更改函数签名。

bool foo(int A1[], int A2[], int len){

    int i;
    if (len == 0){
        return true;

    } else {

        for (i = len - 1; i >= 0; i--){

            if (A1[len - 1] == A2[i]){

                A2[i] = A2[len - 1];
                A2[len - 1] = A1[len - 1];

                bool result = foo(A1, A2, len - 1);

                A2[len - 1] = A2[i];
                A2[i] = A1[len - 1];

                return result;
            }
        }

        return false;
    }
}