【问题标题】:Check if Number Exists in array which first increases then decreases then increases检查数组中是否存在先增加然后减少然后增加的数字
【发布时间】:2014-02-07 11:53:27
【问题描述】:

给定一个数组首先增加然后在某个点减少然后再次增加? 查找给定数 N 是否存在于数组中。

示例 1:

Array = 7,8,3,4,5,6 
number = 7 

答案应该是真的。

示例 2:

Array = 3,4,6,7,8,5,9,10,11  
number = 10

答案应该是真的。 所有数字都是唯一的。

可以通过O(N)中的线性搜索来完成, 我们能不能做得比这少。 (更高效)

【问题讨论】:

  • 一般来说,线性搜索和非线性数组一样好
  • 修改后的三元搜索怎么样,运行两三遍?也许你可以得到O(log N) 时间复杂度?
  • 否,对于未排序的数组搜索(存在查找),难度为 O(N)。
  • 我认为我们不能将其视为简单的未排序数组,因为数组已经具有结构。例如,我们可以在线性时间内对这个数组进行排序。但 user2357112 的示例表明,这种结构最终并不能帮助我们进行搜索。

标签: arrays algorithm search


【解决方案1】:

一般来说,不会。假设我们在 Python 中有以下内容:

l = range(n)

我们随机在其中粘贴-1

if random.random() < 0.5:
    l[random.randrange(len(l))] = -1

判断列表中是否有-1 的唯一方法是查看每个元素,直到找到或没有。列表的结构最终毫无帮助。

【讨论】:

    【解决方案2】:

    线性搜索与非线性数组一样好

    【讨论】:

      【解决方案3】:

      优化算法: -

      1. 如果找到,则对数组中的键使用二进制搜索,然后返回 true。
      2. 如果找不到,请使用线性搜索

      时间复杂度:-

      不成功的搜索:这里我们将同时进行线性搜索和二分搜索,因此对于大输入的 O(N)

      搜索成功:这是我们的优化在某种程度上发挥作用的地方。在二分搜索中,平均有 1/2 的机会最终在数组的右侧进行搜索。因此,平均搜索速度至少快 2 倍。

      优化算法的Java代码和结果:-

      public class UniqueSearch {
          static int linearCount = 0;
          public static boolean binSearch(int[] arr,int key,int high,int low) {
      
      
              while(high>=low) {
                  int mid = (low+high)/2;
                  if(arr[mid]==key) 
                      return(true);
                  if(arr[mid]<key) {
                      low = mid+1;
                  }
                  else {
                      high = mid-1;
                  }
              }
              return(false);
          }
      
          public static boolean linearSearch(int arr[],int key) {
              //System.out.println("linearSearch");
              linearCount++;
              for(int i=0;i<arr.length;i++) {
                  if(key==arr[i]) {
                      return(true);
                  }
              }
              return(false);
          }
      
      
          public static boolean optSearch2(int arr[],int key) {
      
              boolean flag = binSearch(arr, key, arr.length-1,0);
              if(!flag) {
                  return(linearSearch(arr, key));
              }
              return(flag);
          }
      
          public static void main(String[] args) {
      
              int n = 100000;
              int[] arr = new int[n];
              int error = 0;
              Random r = new Random();
              long start = System.currentTimeMillis();
              int totalCount = 0;
              for(int i=0;i<1000;i++) {
                  error = r.nextInt(arr.length-1);
                  for(int k=0;k<error;k++) {
                      arr[k] = 2*k+1;
                  }
                  for(int k=error;k<arr.length;k++) {
                      arr[k] = 2*(k-error);
                  }
                  for(int j=0;j<1000;j++) {
                      int x = r.nextInt(arr.length); 
                      totalCount++;
                          boolean flag = optSearch2(arr,arr[x]);
                          if(!flag) {
                              System.out.println("error");
                          }
      
                  }
              }
              System.out.println("linearSearch Percentage: "+linearCount*100/totalCount);
              System.out.println(System.currentTimeMillis()-start);
          } 
      }
      

      结果:

      运行代码并等待 6-7 秒,您将看到在特殊类型的随机数组上进行随机成功搜索,因为您的问题需要线性搜索大约 30% 次,其余的可以使用 @987654322 中的二进制搜索完成@

      【讨论】:

      • 问题(如 user2357112 的示例所示)是递减段可能非常小,需要线性时间来定位。所以你不能真正利用它来发挥你的优势。您将如何在算法 2 中使用二分搜索?
      • @Teepeemm 在算法 2 中,您可以以 1/4 的概率成功搜索到数组的右数组部分,因此对于成功的搜索,它提供大约 3/4*n/2 次计算,即 3 /8*n 计算成功搜索大 N
      • 我承认如果数组的递减部分很大,那么我们可以进行二分搜索。如果增加的部分大小相同,并且其中一个包含所需的数量。但在给定的例子中,你最坏的情况一定是O(N),我看不出你如何能用这种设置击败线性搜索。
      • @Teepeemm 我并不是说你不能击败 O(N),但你可以将线性搜索的概率降低到 50% 和 50% 以进行二分搜索以实现成功搜索
      【解决方案4】:

      可以在 O(logN) 时间复杂度内完成

      1. 在数组中查找最大元素(称为此枢轴)。这是伪代码

        public static int getMax(int start, int end){
        
        if(start==end)
            return start;
        if(start>end)
            return -1;
        
        int mid = start + (end-start)/2;
        // check if maxima
        if(arr[mid-1]<arr[mid] && arr[mid]>arr[mid+1])
            return mid;
        
        // check slope
        if(arr[mid-1]<arr[mid] && arr[mid]<arr[mid+1]){
            //increasing slope
            return getMax(mid+1, end);
        }
        if(arr[mid-1]>arr[mid] && arr[mid]>arr[mid+1]){
            return getMax(start, mid-1);
        }
        
        return -1;
        }
        
      2. 在枢轴元素上划分数组并运行两个二项式搜索左(增加)和右(减少)

        findElem(int key, int pivot){
          int index = binSearchInc(start, pivot-1);
          if(index>=0)
            return index;
          else 
            return binSearchDec(pivot+1, end);
        }
        

      这两个步骤都需要 O(logN) 时间来执行。

      【讨论】:

        猜你喜欢
        • 2020-08-17
        • 1970-01-01
        • 1970-01-01
        • 2016-08-17
        • 2010-11-22
        • 1970-01-01
        • 2021-10-24
        • 2019-11-19
        • 2019-02-12
        相关资源
        最近更新 更多