码迷,mamicode.com
首页 > 编程语言 > 详细

数据结构与算法分析(1)

时间:2017-09-20 19:40:33      阅读:238      评论:0      收藏:0      [点我收藏+]

标签:最大公约数   查找   style   binsearch   编译   end   最大   结束   break   

1. 最大子序列和的问题
输入样例:4 -3 5 -2 -1 2 6 -2
输出:11
1.1 使用二分法递归求解代码如下(时间复杂度:O(NlogN)):GCC编译C++使用g++命令

int getMax3 (int a, int b, int c)
{
    int max = a;
    if (max < b)
        max = b;
    if (max < c)
        max = c;
    return max;
}
int getMaxSum(const vector<int> &arr, int bgn, int end)
{
    if (bgn >= end)
        return 0;
    int mid = (bgn + end) / 2;
    int leftMaxSum = getMaxSum(arr, bgn, mid);
    
    //此处的起始位置应设置为mid + 1,否则会造成无限递归
    int rightMaxSum = getMaxSum(arr, mid + 1, end);
    
    int leftMaxBorder = 0, leftTmp = 0;
    for (int i = mid; i >= bgn; --i)
    {
        leftTmp += arr[i];
        if (leftTmp > leftMaxBorder)
            leftMaxBorder = leftTmp;
    //    if (leftTmp < 0)    //这个地方不能提前退出,必须完全遍历
    //        break;
    }
    int rightMaxBorder = 0, rightTmp = 0;
    for (int i = mid + 1; i < end; ++i)
    {
        rightTmp += arr[i];
        if (rightTmp > rightMaxBorder)
            rightMaxBorder = rightTmp;
    //    if (rightTmp < 0)
    //        break;
    }
    return getMax3(leftMaxSum, rightMaxSum, leftMaxBorder + rightMaxBorder);
}

1.2 一次性遍历的求解方法如下(时间复杂度O(N)):

int getMaxSubSum(const vector<int> &arr, int bgn, int end)
{
    int maxSum = 0;
    int sumTmp = 0;
    for (int i = bgn; i < end; ++i)
    {
        sumTmp += arr[i];
        if (sumTmp > maxSum)
            maxSum = sumTmp;
        else if (sum < 0)
            sumTmp = 0;
    }
    return maxSum;
}

2. 算法时间复杂度为O(logN)的典型问题:
2.1 对分查找(binary search):时间复杂度(<= log2N)

int binSearch(const vector<int> &arr, int bgn, int end, int target)  //end-尾元素后一位置
{
    int ret = -1;
    while (bgn < end)
    {
        int mid = (bgn + end) / 2;
        if (target == arr[mid])
        {
            ret = mid;
            break;
        }
        else if (target > arr[mid])
            bgn = mid + 1;
        else    
            end = mid;
    }
    return ret;
}

2.2 两个整数最大公约数求解(欧几里德算法):时间复杂度(<= 2logN)

unsigned int getGCD(unsigned int m, unsigned int n)
{
    while (n > 0)
    {
        int rem = m % n;
        m = n;
        n = rem;
    }
    return m;
}

  这里其实运用了递归的思想:m与n的最大公因子即是n与rem(m%n)的最大公因子...,那么,只需要说明n与rem的最大公因子就是m与n的最大公因子即可使这个递归进行下去。所以问题是n与rem的最大公因子为什么就是m与n的最大公因子?

思路:假设m > n,又即使m < n,经过一次遍历后有m > n,m与n的最大公因子是A,则m = xA, n = yA。
  rem = m%n -> m-zn(z = m/n),当rem=0,n即是两者的最大公因子;rem>0,rem=xA - zyA,很显然rem%A = 0
         -> m与n的最大公因子即是n与rem的最大公因子,以此类推

2.3 幂运算:时间复杂度(<= 2logN)

long long pow(long long x, unsigned int n)
{
    if (0 == n)
        return 1;
    if (n % 2)
        return pow( x*x, n/2 ) * x;
    else
        return pow( x*x, n/2 );
}

  以2^15为输入,则恰需要 2log(15) = 6 次乘法运算
  以2^16为输入,则仅需要 4+1(<2log(16)=8) 次乘法运算,也可以修改下代码添加出口判断(if (1 == n))使之成为4次乘法运算,不过需要每次进入pow多判断一次

  PS: 1. 书上以2^62为例,共需9次乘法运算,但所推演算法过程个人觉得有问题。实际过程应该是首先层层运算pow入口参数x*x的值,直至n == 0。
     然后,再逆序层层计算pow*x的值,直至算法结束运算
    2. 代码中语句pow( x*x, n/2 )可以用pow( x, n/2 )*pow( x, n/2 )代替,但是效率会非常低,因其进行了大量的重复性工作

数据结构与算法分析(1)

标签:最大公约数   查找   style   binsearch   编译   end   最大   结束   break   

原文地址:http://www.cnblogs.com/Glory-D/p/7562907.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!