回顾一下算法方面的基础知识:
-- 时间复杂度和空间复杂度 选择排序、冒泡排序、插入排序的细节和时间复杂度分析
-- 二分法的使用和复杂度分析
-- 一道时间复杂度很低的利用异或运算解决的问题
-- 常见时间复杂度的比较
-- 详解递归函数与常见递归函数的复杂度估算(master公式)
--详解对数器的使用
认识时间复杂度:
常数操作(与数据量没有关系,固定时间):数组寻址操作(内存跳一下时间),加减乘除(整型32位),位运算
时间复杂度:一个算法流程中常数操作数量的指标。
(M*N)*O(1):2个for循环的遍历
: :只要高阶项,不要低阶项,也不要高阶项的系数,剩下的记为f(N),时间复杂度为O(f(N)).
评价算法的指标:先看时间复杂度的指标,然后再分析不同数据样本下的实际运行时间,也就是常数项时间。
二分:
[二分法通常用于二分查找。所谓二分,其实就是每次与有序序列中的中值比较,如果比中值小,则去中值的左边序列中查找,如果比中值大,则去中值的右边序列中查找,如果与中值相等,则查找成功。就这样按照上面的步骤循环查找,直到找到或者序列长度为1为止。]
冒泡: 算法思想就是气泡往上冒的样子,2个2个比较,冒一次排好一个数,再冒第二次...
[在长度为n的序列中,每次遍历整个序列,比较前后两个元素,如果后面的这个元素比前面的这个元素小,交换两个元素,这样多次遍历后,知道序列有序。]
选择:第1趟,在待排序记录r[1]~r[n]中选出最小的记录,将它与r[1]交换;第2趟,在待排序记录r[2]~r[n]中选出最小的记录,将它与r[2]交换;以此类推,第i趟在待排序记录r[i]~r[n]中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完毕
[在长度为n的序列中,每次遍历n-i次序列,(i=0,1,2,... ,n)将序列后(n-i)个元素中最大/小的元素放到第i个位置上。]
插入排序:扑克牌整牌,抽到一张牌,排序
插入排序与数据状况有关系,冒泡和选择与数据状况无关系。插入在有序下O(N),无序
[在长度为n的序列中,将序列第 i 个元素有序地插入到前(i-1)个已经有序的元素中,直到序列有序。]
一道时间复杂度很低的利用异或(^)运算解决的问题:
整数型数组中,每个元素均出现两次,除了一个元素例外,如何找出这个元素?能否设计一个线性时间的算法,且不需要额外的存储空间?
使用异或运算符(^)可以O(n)的时间复杂度解决这个问题。
异或运算符的特点是:数a两次异或同一个数b(a=a^b^b)仍然为原值a。对于任何数x,都有x^x=0,x^0=x。
其实O(n)的算法不容易一下子想到,先说说常规的解决思路,有如下两种:
1、对元素的出现次数进行统计,可进行n*n循环,判断元素是否只出现了一次。这样时间复杂度为O(n^2), 不需要额外空间。
2、先对元素进行排序,然后进行相邻两元素的对比,如a1和a2对比,a3和a4对比,如果不同,则前一个元素(a1、a3)就是所要查找的元素。这样的时间复杂度还是比O(n)高。
这两种解法的时间复杂度都比O(n)更高。但是,如果你运用了异或运算符的特点,那么这个问题就很容易解决了,算法复杂度为O(n),且不需要额外空间,像这样:
int singleNumber(int A[], int n) {
int result = 0;
for (int i = 0; i<n; i++)
{
result ^=A[i];
}
return result;
}
对数器的概念和使用
(大数组,贪心策略)
0.有一个你想要测的方法a,
1.实现一个绝对正确但是复杂度不好的方法b
2.实现一个随机样本产生器
3.实现比对的方法
4.把方法a和方法b比对很多次来验证方法a是否正确。
5.如果有一个样本使得比对出错,打印样本分析是哪个方法出错
6.当样本数量很多时比对测试依然正确,可以确定方法a已经正确
额外空间复杂度:为完成算法额外申请的空间
递归行为及时间复杂度:系统栈
任何递归可以改为非递归
master公式:
T(n/b):子过程样本量 a:子过程几次 n^d:剩下的过程
1) log(b,a) > d -> 复杂度为O(N^log(b,a))
2) log(b,a) = d -> 复杂度为O(N^d * logN)
3) log(b,a) < d -> 复杂度为O(N^d)
归并排序的细节与复杂度分析:
时间复杂度O(N*logN),额外空间复杂度O(N)
左右侧分别排序,整体外排。
5 3 6 | 2 0 1 --> 3 5 6 | 0 1 2 准备辅助数组外排
小和问题和逆序对问题(归并排序解决)
小和问题
在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
例子:
[1,3,4,2,5]
1左边比1小的数,没有;
3左边比3小的数,1;
4左边比4小的数,1、3;
2左边比2小的数,1;
5左边比5小的数,1、3、4、2;
所以小和为1+1+3+1+1+3+4+2=16
1 3 4 | 2 5
当前数是cur,右侧有多少数比当前数大 x个cur
L + (R-L) >> 1 不会溢出且 速度快(位运算比算数运算快)
逆序对问题
在一个数组中,左边的数如果比右边的数大,则折两个数构成一个逆序对,请打印所有逆序对。