算法入门篇 一 时间复杂度

时间复杂度

  • 只要高阶项,不要低阶项

局部最小

问题

无序数组,相邻不等,返回一个局部最小的位置,怎么整?

原理

  • 【0】<【1】,0是局部最小
  • 【N-1】<【N-2】,N-1是局部最小
  • 【i-1】<【i】<【i+1】,i是局部最小

方法

  • 二分法,在0-N一定存在局部最小

异或计算(无进位相加)

  • 0异或N=N  N异或N=0
  • 满足交换律和结合律

完成数据的交换

  • 引入第三方变量
int a = 1;
int b = 2;
int c = a;
a = b;
b = c;
  • 单独自身计算,不引入第三方变量
int a = 1;
int b = 2;
a = a + b; //a = 3
b = a - b; //b = 3 - 2 = 1
a = a - b; //a = 3 - 1 = 2
  •  使用异或(前提,值是一样的,但是a和b所处的内存区域是不同的,如果相同会出错)
int a = 1;
int b = 2;
a = a 异或 b; //a = 1 异或 2,b = 2
b = a 异或 b; //a = 1 异或 2, b = 1
a = a 异或 b; //a = 1 异或 2 异或 1 = 2, b = 1
  • 错误使用 
int[] arr = {4,5,3}
int i = 0;
int j = 0;

arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];

for(int c = 0; c < arr.length; c++){
    System.out.println(arr[c]);
}

问题

1,一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数 

代码

public static void printOddTimesNum1(int[] arr){
	int eor = 0;
	for (int cur : arr){
		eor ^= cur;
	}
	System.out.println(eor);
}

原理 

  • 只有一个是奇数项,将所有元素都异或,相同元素就会消失,只剩下奇数的元素,利用到了异或的交换律和结合律

2,一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数 

例子

【1011,0110,0110,1011,1000,0001】
1,让所有元素异或运算,得到eor变量,这个利用相同位置上1的个数,如果是奇数个,则为1,同理,偶数个1为0
2,第一步得到的eor=1001,因为eor的末尾元素为1,则将所有末尾为1的元素进行第二次异或,得到eor’,具体是【1011,1011,0001】,则eor'=0001,eor'也为第一个奇数个元素
3,将eor和eor'进行异或,eor=1001,eor'=0001,则二者计算得到1000为第二个奇数个的元素

引出新的问题 

  • 上面例子中的eor=1001,我们提取最后面位数->1,是如何实现的呢?
  • 例子(方法1)
01101000如何操作变成00001000呢?提取到指定位数的1,其余位数全部清零
假设 a = 01101000
1,计算 a-1,目的是打散最末尾的数字1,a-1 = 01100111
2,计算 a同或a-1 = 01100000,目的是清楚原始最右侧的1
3,计算 a异或(a同或a-1)= 00001000
  • 例子(方法2)

a & (~a +1)
a = 01101000, a取反得到10010111,再 +1 得到10011111
a & (~a +1) = 01101000 & 10011111 = 00001000

算法

public static void printOddTimesNum2(int[] arr){
	int eor = 0;
	for (int i=0;i<arr.length;i++){
		eor ^= arr[i];
		//eor = a ^ b
		//err != 0
		//err必然有一个位置上是1
		int rightOne = eor & (~eor + 1);//提取出最右侧的1
		int onlyOne = 0;//eor'
		for (int cur : arr){
			if((cur & rightOne) == 0){
				onlyOne ^= cur;
			}
		}
	}
	System.out.println(onlyOne + " " + (eor ^ onlyOne));
}

对数器

  • 最简单的方法和优化的方法,使用大量的结果分别测试,如果结果是一致的,说明优化的方法是正确的。

猜你喜欢

转载自blog.csdn.net/CHYabc123456hh/article/details/106602723