算法分析

数学基础

指数

指数加法、乘法、除法、幂

XAXB=XA+B
XAXB=XAB
(XA)B=XAB
XN+XN=2XN

对数

在计算机科学中,除非有特笔的声明,否则所有的对数都是以2为底的。

logAB=logCAlogCB 换底公式
logAB=logA+logB

级数

ni=02i=2N+11

ni=0Ai=AN+11A1

ni=0i2=n(n+n1(2n+1)6

模运算

如果N整除 A-B,那么就说A与B模N同余,记为 AB(modN)
8161(mod/10)

证明方法

归纳法
  基准情形
  归纳假设
  
反证法
  通过反例证明

算法

算法是什么?算法是为求解一个问题需要遵循的、被清楚指定的简单指令的集合。
为什么学习算法?1 算法是用来解决问题的。2 机器学习的时候会用到算法。3 找工作。
算法的特点:1 有穷性,需要在一定的时间范围内完成。(对立面:地老天荒)。2 确定性,第一步做什么,第二步做什么,清清楚楚。3可行性,在当前的计算条件、人力、物力条件下能实现的。4每个算法都要有输入输出。

算法分析

算法分析是分析算法的时间、空间复杂度。使用大O标记法。会涉及到上界、下界。法则:
如果 T1(N)=O(f(N)) T2(N)=O(g(N)) ,那么 T1(N)+T2(N)=O(f(N)+g(N))

如果 T1(N)=O(f(N)) T2(N)=O(g(N)) ,那么 T1(N)T2(N)=O(f(N)g(N))

算法时间复杂度分析中,每一步就是指汇编中的一条指令。空间是指内存暂用字节数。

复杂度分析方法

数循环次数、均摊分析、递归式–主定理

复杂度标记

  1. O(1)
    基本运算:+ - * / % 寻址
  2. O(logn)
    二分查找
  3. O( n1/2 )
    枚举约数。例如查找100的约数有哪些?1,2,4,5,10,20,25,50,100。计算的时候只要从1计算到10即可,因为当找到约数2的时候,也找到了50。所以只需要 n1/2

  4. O(n)
    线性查找

  5. O( n2 )
    朴素最近点对
  6. O( n3 )
    普通矩阵乘法 Floyd最短路(不了解)
  7. O(nlogn)
    归并排序 快速排序期望复杂度 基于比较的排序算法下界
  8. O( 2n )
    枚举全部的子集
  9. O(n!)
    枚举全排列

优秀的复杂度:O(1) < O(logn) < O( n1/2 ) < O(n) < O(nlogn)
可能可以优化的:O( n2 ) < O( n3 ) < O( 2n ) < O(n!)

分析方法之 数数

我之前看过N遍算法书,终究是没看明白时间复杂度与空间复杂度是怎么计算的。前段时间做了leetcode,算是有一点点感觉。最好详细阅读《数据结构域算法分析-java语言描述》第2版 的第2章。在书籍中有说明for循环、顺序语句、if/else语句怎么计算复杂度。也介绍了什么是大O标记法。我还需要再看看书。

分析方法之 均摊分析

因为每次操作数量不同,但是总操作数是一定的,所以可以用均摊分析法。例如Java中的ArrayList的实现。ArrayList是用数组实现的。在初始化的时候会分配一定的空间n。每次add、remove操作都是O(1)。但是当插入数量大于n的时候,会导致一次内存重新分配,会再分配n+ 12n 的空间,再把前n个数,拷贝到新数组。


private void grow(int minCapacity) {
      // overflow-conscious code
      int oldCapacity = elementData.length;
      int newCapacity = oldCapacity + (oldCapacity >> 1);
      if (newCapacity - minCapacity < 0)
          newCapacity = minCapacity;
      if (newCapacity - MAX_ARRAY_SIZE > 0)
          newCapacity = hugeCapacity(minCapacity);
      // minCapacity is usually close to size, so this is a win:
      elementData = Arrays.copyOf(elementData, newCapacity);
  }

那add操作的时间复杂度是多少呢?例如初始n=10,当n=15、22、33、49、73、109….的时候会触发数组扩充操作。假设最终n=109,这期间需要进行 10+15+22+33+49+73=202次操作。平均到每个数字202/109=2。表示为O(1)(关于为什么2表示为O(1)需要看书了解)。

例题

求最大字序列和。给定一个数组nums,里面有正有负,求 jk=inums[k] 的最大值。

解法一 暴力

枚举所有子数组可能的起始下标和结束下标。第4行循环大小为n。第5行循环大小为n-i,但最坏情况是n。第7行循环大小为j-i+1,最坏情况也是n。所以时间复杂度记为O( n3 )。

public static int maxSubSum(int[] nums) {
    int n = nums.length;
    int maxSum = 0;
    for (int i = 0; i < n; i++) {
        for (int j = i; j < n; j++) {
            int thisSum = 0;
            for (int k = i; k <= j; k++) {
                thisSum += nums[k];
            }
            maxSum = Math.max(thisSum, maxSum);
        }
    }
    return maxSum;
}

解法二 优化枚举

解法一中有一些冗余计算。 jk=inums[k]=j1k=inums[k]+nums[j] 。优化以后时间复杂度O( n2 )。

public static int maxSubSum(int[] nums) {
    int n = nums.length;
    int maxSum = 0;
    for (int i = 0; i < n; i++) {
        int thisSum = 0;
        for (int j = i; j < n; j++) {
            thisSum += nums[j];
            maxSum = Math.max(thisSum, maxSum);
        }
    }
    return maxSum;
}

解法三 贪心

这里用到了数组中有正有负的条件。任意一个数加上负数和总是在变小。所以当发现thisSum<0,就让thisSum=0。这样的解法时间复杂度O(n),但是正确性不是很明显,总是需要证明的,同时也需要较高的编程人员水平(相对来说)。算法的优化总是在时间、空间、复杂度之间进行权衡。

public static int maxSubSum(int[] nums) {
    int n = nums.length;
    int maxSum = 0,thisSum = 0;
    for (int i = 0; i < n; i++) {
        thisSum += nums[i];
        maxSum = Math.max(maxSum, thisSum);
        if(thisSum <0 ) thisSum = 0; 
    }
    return maxSum;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值