• 算法导论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;
    }



  • 相关阅读:
    Construct Binary Tree from Preorder and Inorder Traversal
    Construct Binary Tree from Inorder and Postorder Traversal
    Maximum Depth of Binary Tree
    Sharepoint 2013 创建TimeJob 自动发送邮件
    IE8 不能够在Sharepoint平台上在线打开Office文档解决方案
    TFS安装与管理
    局域网通过IP查看对方计算机名,通过计算机名查看对方IP以及查看在线所有电脑IP
    JS 隐藏Sharepoint中List Item View页面的某一个字段
    SharePoint Calculated Column Formulas & Functions
    JS 两个一组数组转二维数组
  • 原文地址:https://www.cnblogs.com/haigege/p/2303968.html
Copyright © 2020-2023  润新知