提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
算法学习Day01
一、时间复杂度是什么?
该算法计算次数相加后取最高阶,无视常数,所剩下的部分
如选择排序 共需要计算n+n-1+n-2+……
等差数列计算公式可得
an²+bn+c
去除低阶与常数,剩下了n²
所以该算法的时间复杂度就是O(n²)
O()最差情况下时间复杂度
θ()平均情况下时间复杂度
Ω()最好情况下时间复杂度
二、简单排序算法
1.选择排序
基本思想:
先假定数组0号位是最小下标,循环到后边找到最小的数,之后交换位置
动图演示:
代码如下:
public class DemoApplication {
public static void main(String[] args) {
int [] arr = {1,2,4,5,6,11,5,53,24,666};
selectsort(arr);
for (int i : arr) {
System.out.println(i);
}
}
public static int[] selectsort(int[] arr){
if(arr.length<2){
return arr ;
}
for (int i = 0; i < arr.length-1; i++) {
int minIndex = i;
for (int j = i+1; j < arr.length ; j++) {
minIndex = arr[j]> arr[minIndex]?minIndex:j;
}
swap(arr,i,minIndex);
}
return arr;
}
public static int [] swap(int[] arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
return arr;
}
}
2.冒泡排序
基本思想:
两层循环,比较相邻元素,如果后者比前者大,那么交换位置,这样一轮循环结束后,最大的一个就会在最后的位置。
动图演示:
代码如下:
package com.example.demo;
public class maopaosort {
public static void main(String[] args) {
int [] arr = {1,2,4,5,6,11,5,53,24,666,12,45,55,4562,6456,243234325,343,35345,45326,54353};
sort123(arr);
for (int i : arr) {
System.out.println(i);
}
}
public static int [] sort123(int [] arr){
for (int i = 0; i < arr.length ; i++) {
for (int j = 0 ; j < arr.length ; j++) {
if(arr[i]<arr[j]){
swap(arr,i,j);
}
}
}
return arr;
}
public static int [] swap(int[] arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
return arr;
}
}
3.插入排序
基本思想:
保证一个段内是有序的
动图演示:
public static void main(String[] args) {
int[] a = {17, 1, 24, 5, 566, 76, 456, 2366, 8632, 233};
sort(a);
for (int i : a) {
System.out.println(i
);
}
}
public static void sort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
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];
}
三、异或运算基础知识
&: 计算时位同1取1
| :计算时只要有一个1 那就取1
~ :取反
^: 相同取0 不同取1;可以看作一种不进位的加法
四、一种更加优雅的交换两个数据的方式:异或运算
交换数据正常来说都会想到一个用中间变量承载数据,再交换的套路,如下图所示:
public static int [] swap(int[] arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
return arr;
}
但或许我们可以选择一种更加优雅的方法来解决眼前的问题:异或运算
异或运算,就是相同取0 ,不同取1,我们可以将它看作一种不进位的加法。
异或运算满足交换律和结合律,
那么可以得到 可以通过
a = a ^ b; //此时: a = a ^ b b = b
b = a ^ b; // a = a ^ b b = a ^ b ^ b 两个b相同取0 b = a
a = a ^ b; // a = a ^ b ^ a a = b b = a;
突出一个优雅。
但需要注意的是,a和b必须占用不同的内存空间****
以后遇到这种情况不妨尝试一下吧~
五、练习题目
1)有一个整数数组,其中有一种数为奇数,其他均为偶数,请问如何取出这个奇数?
2)如果有两种奇数,其他都为偶数,要怎样取出?
第一题:全部异或即可
int [] a = {1,1,2,3,3};
for (int i = 0; i < a.length -1 ; i++) {
a[i] = a[i] ^ a[i+1];
}
for (int i : a) {
System.out.println(i);
}
第二题:
首先全部异或的话,temp = a^b 因为偶数数量的全部被异或掉了。
那么因为a b还存在,所以他们一定有一位不同,不然就会得0.
我们设法取出a b钟不同的一个数,进行分类,那么全部数字会被分成:某一位为1,某一位为0的两个部分。
将两部分分别异或,其他的一定都会被消除掉,剩下的就是奇数位的数。
如何去取出最右一个不同的数:
原数据 :000001100
取反: 111110011
加一: 111110100
原数据与取反加一异或:000000100
如此得到第三位可以作为区分位。
将000000100与数组中数据与运算,同1取1,即可。
具体代码实现:
int [] a = {1,1,2,2,3,3,4,5};
int temp = 0;
for (int i : a) {
temp = temp ^ i;
}
// temp = a ^ b
int rightone = temp &(~temp + 1); //驱护最右边的一个1
int left = 0;
for (int i : a) {
if((i&rightone)==0){
left^=i;
}
}
System.out.println(left+" :" +(left^temp));