zoukankan      html  css  js  c++  java
  • 算法导论P23题目2.37

    请给出一个运行时间为O(n lgn)的算法,使之在给定一个由n个整数构成的集合S和另一个整数x时,判断出S中是否存在有两个其和等于x的元素。

    以下思路一 和 思路二来自 http://blog.csdn.net/magic_coder/article/details/6435098

    思路一 :我们最容易想到的是O(n2)的算法,大致伪码即:

    1 findX(A, x){

    2     for i=0 to length[A] {

    3         key = A[i]

    4             for j=0 to length[A]{

    5                  if(j != i && key + A[j] == x ){return true}

    6     }

    7     return false

    8 }

    这里的算法不符合O(n lgn),所以不行。

    思路二:改进思路一中的算法,使第一层循环里面的4--5行的效率为 lgn。

    既然4-5行的目的是找到某个符合条件的值,那么我想到了二分查找,二分查找是一个最坏O(lgn)的查找算法,但是前提是集合S有序,于是先要进行排序。伪码如下:

    1 findX(A, x){

    2     mergeSort(A, 0, length[A]);

    3     for i=0 to length[A] {

    4         key = A[i]

    6         if( binarySearch(A, x-key, 0, length[A]) != i ){return true}

    7     }

    8     return false

    9 }

    第2行的归并排序运行时间为O(n lgn), 第3-7行的运行时间为O(n)*O(lgn)= O(nlgn),故总运行时间为O(nlgn)。

    思路三来自http://blog.csdn.net/intrepyd/article/details/4340638

    思路三:

    1.        对数组S进行归并排序。

    2.        构造数组S’={z : z=x-y, y∈S},并排序。由于S已经有序,构造与排序可一并完成。

    3.        删除S中重复的元素使仅保留一个,对S’进行同样的操作。

    4.        合并S和S’,并保证合并后有序,这里可以使用归并排序的思想。

    5.        如果在合并后的数组中存在连续两个相同的元素,并且这种元素的个数大于1,那么有解。

    设想在合并后的数组中存在连续两个w,则w分别属于S和S’,那么S中存在y使得w=x-y,即x=y+w。因此,S中元素w和y的和为x。

    步骤1的运行时间为Θ(n lg n),其余步骤运行时间为Θ(n),因此总的时间代价为Θ(n lg n)。

    思路四:前提是所有元素非负

    1 首先通过合并排序对数组元素排序,时间 O(nlgn)

    2 用二分查找方法找到一个数组下标 pEnd,使给定的 key≤array[i], 时间 O(lgn)

       注意: P23页的 2.3-6题的插入排序就可以用这种方法实现

    3 在下标0 - pEnd之间搜索满足条件的数据,这里用到思路二的思想。时间 O((pEnd)lg(pEnd))

    代码如下:

    /*
    * findSumofdata.cpp
    * 算法导论 P.23 2.3-7
    * Created on: 2011-12-27
    * Author: LiChanghai
    */

    #include "myheder.h"

    //该函数寻找下标 pEnd
    bool binaryFind(const int array[ ], int n, int &pEnd, int key)
    {
    /* 找到下标 pEnd,使 key 小于等于 array[pEnd] */
    int low = 0, high = n-1;
    int middle;
    //元素个数大于1时进行二分查找
    while(low < high)
    {
    middle = (low+high)/2;
    if(key <= array[middle])
    high = middle;
    else
    low = middle+1;
    }
    //只剩一个元素时,确定 pEnd 的值
    if(key >= array[low])
    {
    pEnd =low;
    return 1;
    }
    else
    if(low != 0)
    {
    pEnd = low -1;
    return 1;
    }
    else
    return 0; //所有的数据都比 key 大,返回0表示没找到
    }

    bool findSumofdata(int array[ ], int n, int key)
    {
    //首先调用合并排序函数对数组进行排序,时间为 O(nlgn)
    //mergeSort(array);

    // 定义 pEnd, 计算pEnd 使 key≤array[pEnd], 时间为 O(lgn)
    int pEnd;
    //如果所有数据都比key大,显然要找的数据不存在
    if( ! binaryFind(array, n, pEnd, key) )
    return 0;

    //现在在 0--pEnd 之间寻找满足条件的数据,时间小于O((pEnd)lg(pEnd))≤O(nlgn)
    // 首先对于特定的 array[i], 需要寻找一个数a, 使 a+array[i]=key
    // 即需要寻找 a=key-array[i]
    for(int i=0; i != pEnd; ++i) //该语句的时间为 O(pEnd)≤O(n)
    {
    int index=binarySearch(array, i+1, pEnd, key-array[i]); //该句的时间小于 O(lg(pEnd))
    if(index != -1)
    return 1;
    }
    //如果没找到,返回0
    return 0;
    }



  • 相关阅读:
    android slidingview
    关于打工
    android开发基本流程
    android and javascript
    android listview and scrollview
    google收购的公司
    android反编译
    android资料
    colors
    【读书笔记】-- 文本可视化研究综述
  • 原文地址:https://www.cnblogs.com/haigege/p/2303968.html
Copyright © 2011-2022 走看看