常数时间操作
如果一个操作的执行时间不以具体样本量为转移,每次执行时间都是固定时间。称这样的操作为常数时间的操作。
- 常见的算术运算(+、-、*、/、%等)
- 常见的位运算(>>、>>>、<<、|、&、^等)
- 赋值、比较、自增、自减操作等
- 数组寻址操作
如何确定算法流程的总操作数量与样本数量之间的表达式关系?
1,想象该算法流程所处理的数据状况,要按照最差情况来。
2,把整个流程彻底拆分为一个个基本动作,保证每个动作都是常数时间的操作。
3,如果数据量为N,看看基本动作的数量和N是什么关系。
如何确定算法流程的时间复杂度?
当完成了表达式的建立,只要把最高阶项留下即可。低阶项都去掉,高阶项的系数也去掉。
记为:O(忽略掉系数的高阶项)
三个例子
选择排序
冒泡排序
插入排序
评估算法优劣的核心指标
时间复杂度的意义
额外空间复杂度
算法流程的常数项
认识二分法
1)在一个有序数组中,找某个数是否存在
2)在一个有序数组中,找>=某个数最左侧的位置
3)同理2)
4)找局部最小
认识异或运算
例如:
6 ^ 7
6的二进制:110
7的二进制:111
110
^ 111 = 001
异或运算的性质
1)不使用额外变量交换ab
public class ExchangeAB {
public static void main(String[] args) {
int a = 1;
int b= 2;
a = a ^ b;
//a为a^b,b为b
b = a ^ b;
//b此时为a,a为a^b
a = a ^ b;
//a为b,b为a
System.out.println(a+","+b);
}
}
2)一个数组中有一种数出现了奇数次,其他数出现了偶数次,怎么找到并打印这种数
public class FindAOdd {
//寻找那个奇数
public static void findThisNum(int[] arr) {
int eor = 0;
for (int i = 0; i < arr.length; i++) {
eor = eor ^ arr[i];
}
System.out.println(eor);
}
public static void main(String[] args) {
/*
4个1
3个2
4个3
2个4
*/
int[] arr = {1, 4, 2, 3, 1, 2, 2, 1, 3, 3, 1, 3, 4};
findThisNum(arr);//2
}
}
3)怎么把一个int类型的数,提取出最右侧的1
例如:
n = 0…011010001000…0
经过某种变换
n = 0…000000001000…0
思路:n&((~n)+1)
有什么用呢???请看4)
4)一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两种数
思路:
- 用一个变量eor异或数组中所有的数,最后eor一定为a^b
- 由已知条件a!=b,说明eor一定在某一位上有1。此时数组中的所有数被分为两类(假设第x位为0)
- 第x位为0但总个数为偶数的数、a(假设a第x位为0)
- 第x位为1但总个数为偶数的数、b
- 用另一个变量eor‘ 来异或某一类(假设为第x位为0的那一组),那些个数为偶数的数仍不会干扰,最后的eor’ 一定是a,另一组亦然。
public class FindDoubleOdd {
public static void findDoubleOdd(int[] arr) {
int eor = 0;
for (int i = 0; i < arr.length; i++) {
eor = eor ^ arr[i];
//此时eor为a^b
}
int rightOne = eor & (~eor + 1);//提取最右一位为1的数
int seor = 0;
for (int i = 0; i < arr.length; i++) {
//(arr[i] & rightOne) != 0 说明i的x位上和rightOne一样为1
if ((arr[i] & rightOne) != 0) {
seor = seor ^ arr[i];
}
}
System.out.println(seor + " " + (eor ^ seor));
}
public static void main(String[] args) {
/*
3个1
2个2
2个3
3个4
*/
int[] arr = {1, 1, 1, 2, 2, 3, 3, 4, 4, 4};
findDoubleOdd(arr);//1,4
}
}
5)数出一个数的二进制有几位是1
- 先找出这个数二进制最右侧的1
- 抹掉这位的1
- 周而复始直到这个数为0
- 统计抹了几次即为有多少位为1
public class FindBit1Counts {
public static int findBit1Counts(int i){
int count = 0;
while (i !=0){
int rightOne = i&((~i)+1);
count++;
i ^= rightOne;
}
return count;
}
public static void main(String[] args) {
int i = 6;//0110 2个1
System.out.println(findBit1Counts(i));
}
}