时间复杂度
常见的算法时间复杂度:O(1)<O(logN)<O(N)<O(NlogN)<O(N2)<O(2N)<O(N!)
public class TimeComplexity {
public static void main(String[] args) {
long start = System.currentTimeMillis();
algorithm01(10000);
long end = System.currentTimeMillis();
System.out.println(end - start);
}
// 常数O(1):运行次数与n大小呈常数关系,即不随输入数据大小n的变化而变化
public static int algorithm01(int n) {
int a = 1, b = 2;
int x = a * b + n;
return x;
}
// 无论a取多大,都与输入数据大小n无关,因此时间复杂度仍为O(1)
public static int algorithm11(int n) {
int count = 0;
int a = 10000;
for (int i = 0; i < a; i++) {
count++;
}
return count;
}
// 线性O(N):循环运行次数与n大小呈线性关系
public static int algorithm02(int n) {
int count = 0;
for (int i = 0; i < n; i++) {
count++;
}
return count;
}
// 虽然是两层循环,但第二层与n大小无关,因此整体仍与n呈线性关系
public static int algorithm12(int n) {
int count = 0;
int a = 10000;
for (int i = 0; i < n; i++) {
for (int j = 0; j < a; j++) {
count++;
}
}
return count;
}
// 平方O(N^2):两层循环相互独立,都与n呈线性关系,因此总体与n呈平方关系
public static int algorithm03(int n) {
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
count++;
}
}
return count;
}
// 指数O(2^N):指数阶常出现于递归
public static int algorithm04(int n) {
if (n <= 0) {
return 1;
}
int count1 = algorithm04(n - 1);
int count2 = algorithm04(n - 1);
return count1 + count2;
}
// 阶乘O(N!):阶乘常使用递归实现
public static int algorithm05(int n) {
if (n <= 0) {
return 1;
}
int count = 0;
for (int i = 0; i < n; i++) {
count += algorithm05(n - 1);
}
return count;
}
// 对数O(logN):对数阶与指数阶相反,指数阶为"每轮分裂出两倍的情况" ,而对数阶是"每轮排除一半的情况"。
// 对数阶常出现于二分法、分治等算法中,体现着"一分为二"或"一分为多"的算法思想
public static int algorithm06(int n) {
int count = 0;
float i = n;
while (i > 1) {
i /= 2;
count++;
}
return count;
}
// 线性对数(NlogN):两层循环相互独立,第一层和第二层时间复杂度分别为O(logN)和O(N)
// 线性对数阶常出现于快速排序、归并排序、堆排序等排序算法中
public static int algorithm07(int n) {
int count = 0;
float i = n;
while (i > 1) {
i = i / 2;
for (int j = 0; j < n; j++) {
count++;
}
}
return count;
}
}
空间复杂度
常见的算法空间复杂度:常见的算法空间复杂度:O(1)<O(logN)<O(N)<O(N2)<O(2N)
public class SpaceComplexity {
public static void main(String[] args) {
long start = System.currentTimeMillis();
algorithm01(10);
long end = System.currentTimeMillis();
System.out.println(end - start);
}
// 普通常量、变量、对象、元素数量与输入数据大小n无关的集合,皆使用常数大小的空间
public static void algorithm01(int n) {
int NUM = 0;
int[] nums = new int[10];
Node node = new Node(0);
Map<Integer, String> map = new HashMap<>();
map.put(0, "0");
}
// test()调用了n次,但每轮调用后test()已返回,无累计栈帧空间使用,因此空间复杂度仍为O(1)
public static void algorithm11(int n) {
for (int i = 0; i < n; i++) {
Node.test();
}
}
// 元素数量与n呈线性关系的任意类型集合(常见于一维数组、链表、哈希表等),皆使用线性大小的空间
public static void algorithm02(int n) {
int[] num1 = new int[n];
int[] num2 = new int[n / 2];
ArrayList<Node> nodes = new ArrayList<>();
for (int i = 0; i < n; i++) {
nodes.add(new Node(i));
}
HashMap<Integer, String> map = new HashMap<>();
for (int i = 0; i < n; i++) {
map.put(i, String.valueOf(i));
}
}
// 递归调用期间,会同时存在n个未返回的algorithm12()函数,因此使用O(N)大小的栈帧空间
public static int algorithm12(int n) {
if (n <= 1) {
return 1;
}
return algorithm12(n - 1) + 1;
}
// 平方O(N^2):元素数量与n呈平方关系的任意类型集合(常见于矩阵),皆使用平方大小的空间
public static void algorithm03(int n) {
int[][] arr = new int[n][n];
List<List<Node>> lists = new ArrayList<>();
for (int i = 0; i < n; i++) {
List<Node> nodes = new ArrayList<>();
for (int j = 0; j < n; j++) {
nodes.add(new Node(j));
}
lists.add(nodes);
}
}
// 指数O(2^N):指数阶常见于二叉树、多叉树
// 对数O(logN):对数阶常出现于分治算法的栈帧空间累计(快速排序)、数据类型转换(数字转字符串)等
}
class Node {
int val; // 变量
Node next; // 动态数组
// 动态对象
Node(int x) {
val = x;
}
static void test(){}
}