认识复杂度和简单排序算法
常数时间的操作
一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。
时间复杂度为一个算法流程中,常数操作数量的一个指标。常用O(读作big O)来表示。
在表达式中,只要高阶项,不要低阶项,也不要高阶项的系数,剩下部分如果是f(N),那么时间复杂度为O(f(N))。
评价一个算法流程的好坏,先看时间复杂度,然后再分析不同数据样本下的实际运行时间,也就是“常数项时间”。
选择排序
时间复杂度0(N^2),额外空间复杂度0(1)
//升序排列
public static void selectionSort(int arr[]){
if(arr == null|| arr.length<2){
return;
}
for(int i=0;i<arr.length-1;i++){ // 0 ~ N-1
int minValueIndex=i;
for (int j = i+1; j <arr.length ; j++) { // i ~ N-1
minValueIndex=arr[j]<arr[minValueIndex]?j:minValueIndex;
}
swap(arr,i,minValueIndex);
}
}
public static void swap(int []arr,int i,int j){
int tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
冒泡排序
时间复杂度0(N^2),额外空间复杂度0(1)
public static void bubbleSort(int[] arr){
if(arr == null || arr.length<2){
return;
}
for(int e=arr.length-1;e>0;e--){
for (int i = 0; i < e; i++) {
if(arr[i]>arr[i+1]){
swap(arr,i,i+1);
}
}
}
}
public static void swap(int []arr,int i,int j){
int tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
补充知识点:异或运算
一、
0^N==N
N^N==N
二、
异或运算满足交换律结合律
三、利用异或运算不用额外变
量交换两个数
例如,如上swap代码可改为如下形式:
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];
/*int tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;*/
}
但是要注意,若要使用异或运算交换两个数,这两个数指向的内存空间一定不能相同,即在函数swap中,一定要保证i≠j
四、一个数组中有一种数出现了奇数次,其他数出现了偶数次,怎么找这一个数
/*解决思路就是将所有数异或一遍
偶数个数的数异或后为0,奇数个异或后剩下原来的数
3^3^2^2^23^23^7^7^7^34^34
= (3^3)^(2^2)^(23^23)^(7^7)^7^(34^34)
= 0^0^0^0^7^0
= 7
*/
public static void main(String[] args) {
int [] arr=new int[]{3,3,2,2,23,23,7,7,7,34,34};
int num=0;
for(int i:arr){
num^=i;
}
System.out.println(num);
}
五、一个数组中有两种数出现了奇数次,其它数出现了偶数次,怎么找到这两个数
/*
解决思路:
对于数组arr[1...N],要找到出现奇数次的数,定义为a和b
eor=arr[1]^a[2]^...^arr[N]=a^b
又因a和b一定不相等(题目给定条件),那么eor一定不为0,eor的二进制形式一定存在某一位为1,假设eor二进制形式的第7位为1,那么将数组分为两大阵营:数的二进制形式第7位为1,定义为arr1,数得二进制形式第7位为0,定义为arr2,那么可以知道数a,b分别在两个数组中
则:
onlyOne=arr1[1]^arr[2]^...^arr[m]=a|b
此时,求出其中一个数为onlyOne,另一个数为onlyOne^eor
*/
public static void main(String[] args) {
int [] arr=new int[]{3,3,2,2,23,23,7,7,7,34,34,666,666,666};
int eor=0;
for(int i:arr){
eor^=i; //a^b
}
int rightOne=eor & (~eor +1);//提取出最右边的1
int onlyOne = 0;
for(int i:arr){
if((i&rightOne)==1){
onlyOne^=i;
}
}
System.out.println(onlyOne+" "+(onlyOne^eor));
}
二分法
1.在一个有序数组中,找某个数是否存在
//二分查找 --对于升序数组
public static int binarySearch(int arr[],int target){
int left=0,right=arr.length-1;
if(left>right||target>arr[right]||target<arr[left]) return -1
while(left<=right){
int mid=left+((right-left)>>1);
if(arr[mid]==target) {
return mid; //找到了
}else if(arr[mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
return -1; //没找到
}
2.在一个有序数组中,查找元素第一次出现的位置
//查找元素第一次出现的位置 --- 升序数组(有重复)
public static int binarySearch_FirstAppear(int arr[],int tartet){
int left=0,right=arr.length-1;
int mid=0;
while(left<right){
mid=left+((right-left)>>1);
if(arr[mid]>=tartet){
right=mid;
}else{
left=mid+1;
}
}
if(arr[left]==tartet) return left; //找到了
else return -1;//没找到
}
3.在一个有序数组中,查找元素最后一次出现的位置
//查找元素最后一次出现的位置 --- 升序数组(有重复)
//mid=(left+right+1)/2;---注意
public static int binarySearch_LeastAppear(int arr[],int target){
int left=0,right=arr.length-1,mid=0;
while(left<right){
mid=(left+right+1)/2;//注意
if(arr[mid]<=target){
left=mid;
}else{
right=mid-1;
}
}
if(arr[left]==target) return left; //找到了
else return -1; //没找到
}
4.局部最小值问题:已知一个无序数组,求该数组中一个局部最小的位置(若有多个局部最小位置,找出一个即可)。
//局部最小
/*
思路:
一个无序数组arr[],一定存在局部最小,设mid为该数组的
中间位置,如果该位置比它的左边元素大,那么局部最小一定
在它的左边存在;如果该位置比它右边元素大,那么局部最小
一定在它的右边存在;如果该位置小于左右两边,那么该位置
是一个局部最小位置。情况分为如下:
1.arr == null || arr.length == 0:数组不存在或数组元素空
2.arr.length==1:只有一个元素,该元素即局部最小
3.arr.length>2:
1)情况一:局部最小在数组第一个位置 arr[0]<arr[1]
2)情况二:局部最小在数组最后一个位置 arr[arr.length-1]<arr[arr.length-2]
3)情况三:局部最小在数组最后一个和第一个的中间某个位置
*/
public static int localSmallest(int arr[]){
if(arr==null||arr.length<1) return -1;//数组不存在或没有元素:不存在局部最小
if(arr.length==1) return 0;//只有一个元素,该元素就是局部最小
//情况一:局部最小在数组第一个位置
if(arr[0]<arr[1]){
return 0;
}
//情况二:局部最小在数组最后一个位置
if(arr[arr.length-1]<arr[arr.length-2]){
return arr.length-1;
}
//情况三:局部最小在数组最后一个和第一个的中间某个位置
int low=1,high=arr.length-2,mid=0;
while(low<high){
mid=low+((high-low)>>1);
if(arr[mid]>arr[mid-1]){
high=mid-1;
}else if(arr[mid]>arr[mid+1]){
low=mid+1;
}else{
return mid;
}
}
return low;
}