需要一个不用具体的测试数据和测试环境,就可以粗鲁的估计算法的执行效率的方法。这个方法称为复杂度,记做大写的 O (数据结构与算法的精髓)
时间复杂度
用步数作为时间复杂度的计算,步数:可以理解为数组的每次索引值得读取,就算做一步,也称为 unit_time。
案例 1.数组值获取(O(1))
获取数组中第四个位置的值
int a[] = {0, 1, 2, 3, 4, 5, 6};System.out.println(a[3]); // step1
step1,获取下标为3的数组值,把这个时间称为1步。 在计算机底层,计算机可以通过一步跳到任意一个索引位置读取数据,这个时间也叫单位时间unit_time。 问题:为什么计算机可以一步读取数据索引值?
时间复杂度:常数时间 —— O(1)
函数图:(表示程序运行时间f(x)与数组长度(x)关系)
猜数字游戏(O(logN))
计算N的阶乘(O(N))

public int factorial(int n) {int result = 1; //step1for (int i = 1; i <= n; i++) { //step2result *= i; // step3}return result;}


计算数组中所有组合方式(O(N^2))
public void combine(String args[]) {for (int i = 0; i < args.length; i++) { //step1for (int j = i + 1; j < args.length; j++) { //step2System.out.println(args[i] + args[j]); //step3}}}
总结
- 规律:只保留最大趋势公式,指数>线性>对数>常数
- 计算复杂度的时候只看for循环嵌套情况。
- 写代码的时候,线性复杂度代替指数复杂度就是大大的性能优化
空间复杂度
以一个基础数据类型值作为一个基础单位。
O(1)
O(N)int a = 0;int j = 0;
int a[] = new int[n]
优先考虑时间复杂度
因为计算机内存足够大,(摩尔定律)。性能优化案例——二分法查找
线性查找O(N)
public static int find(int[] array, int aim) {for (int i = 0; i < array.length; i++) {if (aim == array[i]) {return i;}}return -1;}
二分查找O(log(N))
性能对比:public static int find(int[] array, int aim) {// 初始化left = 最左侧, right = 最右侧int left = 0;int right = array.length - 1;// 当left > right则表示遍历完成while (left <= right) {// 获取中间的值int middle = (left + right) / 2;int middleValue = array[middle];if (middleValue == aim) {// 已经找到目标return middle;} else if (middleValue < aim) {// 目标在middle的右侧,重置leftleft = middle + 1;} else {// 目标在middle的左侧,重置rightright = middle - 1;}}return -1;}
练习匹配字符串
str1.compareTo(str2)
返回值为负数表示str1在str2前面,反之在后面。
```java import java.util.ArrayList; import java.util.Comparator;"Kelly".compareTo("Kevin") // 结果为-10"Kevin".compareTo("Kelly") // 结果为10
public class Address {
public static int find(ArrayList
String value = array.get(middle);if(value.compareTo(aim)==0){return middle;}else if(value.compareTo(aim)<0){left = middle + 1;}else{right = middle - 1 ;}}return -1;
}
public static void main(String[] args) {
ArrayList
int result1 = find(array, "Kelly");if (result1 == -1) {System.out.println("Kelly 不存在名单中");} else {System.out.println("Kelly 存在名单中,位置是 " + result1);}int result2 = find(array, "Edith");if (result2 == -1) {System.out.println("Edith 不存在名单中");} else {System.out.println("Edith 存在名单中,位置是 " + result2);}
} }
<a name="14Lk1"></a>## 性能优化案例——二次问题
数字数组为:[0, 8, 2, 3, 5, 6, 2, 10, 8] 重复数字为:[8, 2]
<a name="OEW7I"></a>### 暴力破解(O(N^2))每次取一个元素,依次判断和之后的元素是否有重复。<br />```javapublic static ArrayList<Integer> repeat(int[] array) {ArrayList<Integer> result = new ArrayList<>();for(int i = 0; i < array.length; i++){// 以此判断i位置元素和后面j位置元素是否相等for(int j = i + 1; j < array.length; j++){if(array[i] == array[j]){result.add(array[i]);}}}return result;}
标记法(O(N))
申明一个标记数组用来标记每个数是否重复。
空表示不存在,1表示存在。
public static ArrayList<Integer> repeat(int[] array) {//保存重复值ArrayList<Integer> result = new ArrayList<>();int[] exists = new int[11];for (int i = 0; i < array.length; i++) {int value = array[i];// 如果当前位置已经为1,则表示重复if (exists[value] == 1) {result.add(value);} else {// 否则将当前位置设置为1exists[value] = 1;}}return result;}
字符串查重
import java.util.ArrayList;public class Second {public static ArrayList<Character> repeat(String str) {ArrayList<Character> result = new ArrayList<>();int extists []= new int [26];for (int i=0;i<str.length() ;i++ ){char value = str.charAt(i);// 或者if (extists[value-'a']==1){ 字母a 的ascll码值为97if (extists[value-97]==1){result.add(value);} else{extists[value-97]=1;}}return result;}public static void main(String[] args) {String str = "abcdkioudofanzdfpqwe";System.out.println(repeat(str));}}

