【问题标题】:Write an algorithm in C of cost O(log(n)) with divide and conquer approach用分治法编写成本为 O(log(n)) 的 C 算法
【发布时间】:2020-11-02 22:29:11
【问题描述】:

我必须在 C 中编写一个函数,该函数将数组和数组的维度作为输入。 我们假设该数组具有以下特征:

  1. 数组中的每个元素都不同
  2. 数组的第一个元素是奇数,其余元素是偶数
  3. 数组中至少有一个奇数元素和一个偶数元素

该函数必须使用分而治之的方法返回偶数元素的第一个索引,并且算法的成本应该是 O(log(n))。

在正常情况下,我会使用这样的函数:

int foo(int v[], int n){
   for(int i=0; i<n; i++){
    if(v[i]%2==0)
       return i; 
   }
}

但我不知道如何用分而治之的方法解决这个问题。 是否可以使用修改版的合并排序或快速排序算法来解决问题?

【问题讨论】:

  • 提示:看看二分搜索。
  • 用笔和纸。创建一些这样的数组。您真的必须逐个查看数组才能找到奇数变为偶数的点吗?
  • 或者换一种说法。我这里有这样一个数组,有 1000 个条目。您可以要求单个条目来查找边界。你会问我索引 1,2,3,4,5,6, ...125, ...250,... 500, .... 997, 998, 999 吗?
  • 这与在排序数组中搜索数字没有太大区别,您查看中间索引,然后如果没有找到重做中间或好的方面等,所以每次将大小除以 2复杂度是 log2(n),这里好的一面取决于奇数/偶数
  • 为了添加到其他 cmets,二分搜索背后的想法类似于您在印刷字典或电话簿中进行搜索的方式。想象一下,你有一本有数千页的大书,里面有奇数和偶数。 如何找到边界?

标签: arrays c algorithm function sorting


【解决方案1】:

这样想: 你的输入是 (1,3,5,7,......,2,4,6,8),它的长度是 n。

你的输出肯定不会是 0(你知道这很奇怪),但也可能不是最后一个。

divide et impera 背后最重要的概念是更容易征服更小的事物。所以把你的数组分成两部分,只看一侧,确保另一部分不包含你的结果。

假设我们的数组(从现在起称为“a”)的索引从 0 到 n-1 (a[n-1] = 8)。让我们检查一下中间,所以首先我们需要一个索引。

int mid = (0 + n-1)/2

什么是[中]?

  • 很奇怪吗?然后我们要看右边,从mid+1到n-1

  • 是吗?我们有两种可能:

    • mid-1 是一个有效的索引并且是 a[mid-1] 奇数吗?那么 a[mid] 是第一个偶数元素,mid 是结果
    • else 从 0 到 mid-1 看左边

然后递归地执行它:)

我不太习惯C所以我会写伪代码

int exercise(int[] a, int n) {
   return exerciseRecursive(a, 0, n-1);
}

int exerciseRecursive(int[] a, int start, int end) {
    if (start>end) {
       return -1; //there is no even element
    }
    int mid = (start + end)/2;
    if (a[mid]%2==1) { //odd
       return exerciseRecursive(a,mid+1,end);
    }
    else {
       if (mid-1>=0 && a[mid-1]%2==1) { //the current element is even and the previous is odd
           return mid;
       }
       else {
          return exerciseRecursive(a,start,mid-1);
       }
      
       
    }
}

【讨论】:

    【解决方案2】:

    您可以使用修改后的二进制搜索来查找偶数元素开始的索引。

    在每一步,我们搜索剩余元素的左半部分或右半部分:

    int foo(int v[], int n){
        int l = 0;
        int h = n-1;
    
        while (l < h) {
            int m = (l + h) / 2; // `l + h` may overflow, but ignoring that for simplicity...
    
            if (v[m] % 2 != 0) {
                l = m + 1; // Search in the left half if `v[m]` is odd.
                // Note that the `+ 1` is important to prevent an infinite loop.
            } else {
                h = m; // Search in the right half if `v[m]` is even.
            }
        }
    
        return l;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-22
      • 2015-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-07
      • 2022-07-22
      • 2015-06-12
      • 2021-09-25
      相关资源
      最近更新 更多