思想:分为已排序和未排序部分,将未排序部分依次插入已排好序的部分
时间复杂度:最好情况下 O(n) 最坏情况下 逆序 o(n2)
插入相比于冒泡 性能要好 因为 冒泡每次交换时需要3次赋值,而插入算法则只有依次赋值操作
public void insertSort(int[] nums){
for (int i=1;i<nums.length;i++){
int tmp=nums[i];
int j=i-1;
for (;j>=0;j--){
if (nums[j]>tmp){
nums[j+1]=nums[j];
}else {
break;
}
}
nums[j+1]=tmp;
}
}
每一次比较相邻两各数的大小
时间复杂度:最好情况下 O(n)(优化后的) 最坏情况下 逆序 o(n2)
public void buble(int[] nums){
for(int i=0;i<nums.length;i++){
//提前退出冒泡循环
boolean flag=false;
for (int j=0;j<nums.length-i-1;j++){
if (nums[j]>nums[j+1]){
int tmp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=tmp;
flag=true;
}
}
if(!flag){
break;
}
}
}
归并算法很稳定 ,最坏和最优以及平均时间复杂度都是 O(n)
思路:先划分,然后在合并 使用递归方式
public class MergeSort {
public void mergeSort(int[] nums){
merge(nums,0,nums.length-1);
}
private void merge(int[] nums,int start,int end){
if(start>=end){
return;
}
int mid=(start+end)/2;
//先排序左侧
merge(nums,start,mid);
//排序右侧
merge(nums,mid+1,end);
//将两个数组合并
int i=start;
int j=mid+1;
int k=0;
int[] tmp=new int[end-start+1];
while (i<=mid &&j<=end){
if (nums[i]>nums[j]){
System.out.println("k:"+k);
tmp[k++]=nums[j++];
}else {
tmp[k++]=nums[i++];
}
}
if(i>mid){
while (j<=end){
tmp[k++]=nums[j++];
}
}else {
while (i<=mid){
tmp[k++]=nums[i++];
}
}
for (int n=0;n<tmp.length;n++){
nums[start+n]=tmp[n];
}
}
}
归并排序的优化
当 if( nums[mid] > nums[mid+1] ) 再进行合并
归并排序的优化二:
if( r-l < 15 ) 则使用插入排序
当 有序时,复杂度为O(n2) 平均复杂度 O(nlogn)
- 思路:取首位 v 大于 V 小于 v 三部分 ,然后对各个部分进行排序
public void quickSort(int nums[],int l,int r){
if (l>=r){
return;
}
int index=partation(nums,l,r);
quickSort(nums,l,index-1);
quickSort(nums,index+1,r);
}
//划分为3部分 index 比index 小 比index大
private int partation(int[] nums, int l, int r) {
int tmp=nums[l];
int index=l;
//nums[l+1,index] <nums[index] nums[index+1,r)> nums[index]
for (int i=l+1;i<=r;i++){
if (nums[i]<tmp){
swap(nums,index+1,i);
index++;
}
}
swap(nums,index,l);
return index;
}
private void swap(int[] nums, int j, int k) {
int tmp=nums[j];
nums[j]=nums[k];
nums[k]=tmp;
}
- O(n) 时间复杂度 求无序数组的第k大元素
- 十个接口访问日志文件,合并为一个文件
先构建十条io流,分别指向十个文件,每条io流读取对应文件的第一条数据,然后比较时间戳,选择出时间戳最小的那条数据,将其写入一个新的文件,然后指向该时间戳的io流读取下一行数据,然后继续刚才的操作,比较选出最小的时间戳数据,写入新文件,io流读取下一行数据,以此类推,完成文件的合并, 这种处理方式,日志文件有n个数据就要比较n次,每次比较选出一条数据来写入,时间复杂度是O(n),空间复杂度是O(1),几乎不占用内存,这是我想出的认为最好的操作了,希望老师指出最佳的做法!!!
1 求平方根,要求精确到小数点后6位
2 查找第一个值等于给定值的元素,有序数组且从大到小
public int bsearch(int[] nums,int target){
int low=0;
int high=nums.length-1;
while (low<=high){
int mid=low+((high-low)>>1);
if (nums[mid]>target){
high=mid-1;
}else if(nums[mid]<target){
low=mid+1;
}else {
if(mid==0 || nums[mid-1]!=target){
return mid;
}
high=mid-1;
}
}
return -1;
}
3 查找第一个大于等于给定值的元素
public int bsearch2(int[] nums,int target){
int low=0;
int high=nums.length-1;
while (low<=high){
int mid=low+((high-low)>>1);
if (nums[mid]>=target){
if (mid==0 ||nums[mid-1]<target){
return mid;
}
high= mid-1;
}else{
low=mid+1;
}
}
return -1;
}
4 查找最后一个小于等于给定值的元素
public int bsearch3(int[]nums,int target){
int low=0;
int high=nums.length-1;
while (low<=high){
int mid=low+((high-low)>>1);
if(nums[mid]<=target){
if(mid==0 || nums[mid+1]>target){
return mid;
}
low=mid+1;
}else {
high=mid-1;
}
}
return -1;
}
5 如何快速定位 ip对应的省份地址
[202.102.133.0, 202.102.133.255] 山东东营市
[202.102.135.0, 202.102.136.255] 山东烟台
[202.102.156.34, 202.102.157.255] 山东青岛
[202.102.48.0, 202.102.48.255] 江苏宿迁
[202.102.49.15, 202.102.51.251] 江苏泰州
[202.102.56.0, 202.102.56.255] 江苏连云港
在庞大的地址库中逐一比对 IP 地址所在的区间,是非常耗时的,
假设我们有 12 万条这样的 IP 区间与归属地的对应关系,如何快速定位出一个 IP 地址的归属地呢?
1将ip地址转换为 32 整型
2 从小到大排序
3 找到最后一个小于要找的ip的起始ip区间,在这个区间查找,没有则不存在
6 如果有一个有序循环数组,比如4,5,6,1,2,3。针对这种情况,如何实现一个求“值等于给定值”的二分查找算法?
leetcode 33