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

1. 最大子序列和的问题

输入样例:4 -3 5 -2 -1 2 6 -2
输出:11

1.1 二分法递归求解 - 时间复杂度:O(NlogN)

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 &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 &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 &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))