1.概论
1.固定时间操作:int ---32位 固定时间的操作 比如 数组 在内存是连续的位置
但例如LinkedList 在内存中是一个节点一个节点的查找 ---->>> 所以不是固定时间的操作
2.时间复杂度 O()
将所有的常数的去掉,得到最高阶的部分,an^2 + bn + c ---->>>> O(n^2)
常数时间的操作 确定算法流程的总操作数量与样本数量之间的表达式关系 只看表达式最高阶项的部分
3.排序算法
(1)选择排序
public static void selectionSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 0; i < arr.length - 1; i++) {
int index = i;
for (int j = i + 1; j < arr.length; j++) {
index = arr[j] < arr[index] ? j:index;
}
swap(arr,i,index);
}
}
public static void swap(int[] arr,int i,int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
(2)冒泡排序
public static int[] BubbleSort(int[] arr) {
if (arr == null || arr.length < 2) {
return arr;
}
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 -j; j ++) {
if (arr[j] > arr[j+1]) {
int tmp = arr[i];
arr[i] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
public static int[] bubbleSort(int[] arr) {//代码优化
if (arr == null || arr.length < 2) {
return arr;
}
for (int i = 0; i < arr.length - 1; i++) {
boolean isSorted = true;//有序标记,每一轮的初始是true
for (int j = 0; j < arr.length -i - 1; j++) {
if (arr[j + 1] < arr[j]) {
isSorted = false;//有元素交换,所以不是有序,标记变为false
int t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
//一趟下来是否发生位置交换,如果没有交换直接跳出大循环
if(isSorted )
break;
}
return arr;
}
(3)插入排序
过程: 想让arr[00]上有序,这个范围只有一个数,当然是有序的。 想让arr[01]上有序,所以从arr[1]开始往前看,如果arr[1]<arr[0],就交换。否则什么也不做。 … 想让arr[0i]上有序,所以从arr[i]开始往前看,arr[i]这个数不停向左移动,一直移动到左边的数字不再比自己大,停止移动。 最后一步,想让arr[0N-1]上有序, arr[N-1]这个数不停向左移动,一直移动到左边的数字不再比自己大,停止移动。
if (arr == null || arr.length < 2) {
return;
}
for (int i = 1; i < arr.length; i++) {
for (int j = i -1; j>=0 && arr[j] > arr[j+1]; j--) {//这里的j+1始终指向我们开始盯得数
swap(arr, j, j+1);
}
}
}
public static void swap(int[] arr, int i, int j) {
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];
}
如果某个算法流程的复杂程度会根据数据状况的不同而不同,那么你必须要按照最差情况来估计。很明显,在最差情况下,如果arr长度为N,插入排序的每一步常数操作的数量,还是如等差数列一般所以,总的常数操作数量 = a (N^2) + bN + c (a、b、c都是常数)所以插入排序排序的时间复杂度为O(N^2)。
(4)额外空间复杂度---自主空间和输入无关的
- 需要实现一个算法流程,在实现算法流程的过程中,你需要开辟一些空间来支持你的算法流程。
- 作为输入参数的空间,不算做额外空间
- 作为输出结果的空间,也不算额外空间------因为这些都是必要的、和现实目标有关的。所以都不算但除此之外,你的流程如果还需要开辟空间才能让你的流程继续下去。这部分空间就是额外空间。
- 如果你的流程只需要开辟有限几个变量,额外空间复杂度就是O(1)
(5)常数项-----同样时间复杂度的流程比较常数项----如果两个时间复杂度一样的算法,你还要去在时间上拼优劣,就进入到拼常数时间的阶段,简称拼常数项
例如:插入与冒泡排序---时间的复杂度相同O(n)
生成随机数据直接测-------
(6)最优解 ---时间复杂度尽可能的低的情况下,空间尽可能的少。一般说起最优解都是忽略掉常数项这个因素的,因为这个因素只决定了实现层次的优化和考虑,而和怎么解决整个问题的思想无关
排名从好到差: O(1) O(logN) O(N) O(N*logN) O(N^2) O(N^3) … O(N^K) O(2^N) O(3^N) … O(K^N) O(N!)
2.二分
在有序数组中找,一次砍一半
(1)数组的有序排列的到
(2)防止内存溢出
---->>>>> mid = L + [(R-L)>>1]
if (sortedArr == null || sortedArr.length == 0) {
return false;
}
int L = 0;
int R = sortedArr.length - 1;
while (L < R) {
if (sortedArr[mid] == num) {
return true;
}
else if (sortedArr[mid] > num) {
R = mid - 1;
} else {
L = mid + 1;
}
}
return soredArr[i] = num;
}
(3)局部最小值问题
if (arr == null || arr.length == 0) {
return -1;
}
if (arr.length == 1 || arr[0] < arr[1]) {
return 0;
}
if (arr[arr.length - 1] < arr[arr.length - 2]) {
return arr.length - 1;
}
int right = arr.length - 2;
int left = 1;
int mid = 0;
while (left < right) {
mid = left + (right - left) >> 1;
if (arr[mid] > arr[mid - 1]) {
right = mid - 1;
} else if (arr[mid] < arr[mid + 1]) {
left = mid + 1;
} else {
return ;
}
return left;
}
}