数据结构与算法笔记2

数据结构与算法

P4 认识O(Nlog N)的排序

递归方法

mid=(L+R)/2 可能会溢出

mid=L+(R-L)/2 >>> mid=L+(R-L)>>1[二进制右移等价于相除,左移等价于相乘]

public static int process(int[] arr, int L,int R){
	if(L==R){
		return arr[L];
	}
	int mid=L+((R-L)>>1);//中点
	int leftMax=process(arr,L,mid);
	int rightMax=process(arr,mid+1,R);
	return Math.max(leftMax,rightMax);
}

Master 公式:
T ( N ) = a ∗ T ( N b ) + O ( N d ) T(N)=a*T(\frac{N}{b})+O(N^d) T(N)=aT(bN)+O(Nd)
a:子问题次数 N/b:子问题规模

T(N)=2*T(N/2)+O(1)

满足master公式的递归,若

  1. log_b a<d O(N^d)

  2. log_b a>d O(N^(log_b a))

  3. log_b a==d O(N^d*log N)

    题目一 归并排序

public static void process(int[] arr,int L,int R){
	if(L==R){
		return;
	}
	int mid=L+((R-L)>>1);
	process(arr,L,mid);
	process(arr,mid+1,R);
	merge(arr,L,mid,R);
}
public static void merge(int[] arr,int L,int M,int R){
	int[] help=new int[R-L+1];
	int i=0;
	int p1=L;
	int p2=M+1;
	while(p1<=M && p2<=R){
		help[i++]=arr[p1]<=arr[p2]? arr[p1++]:arr[p2++];
	}
	while(p1<=M){
		help[i++]=arr[p1++];
	}
	while(p2<=R){
		help[i++]=arr[p2++];
	}
	for(i=0;i<help.length;i++){
		arr[L+i]=help[i];
	}
}

T(N)=2T(N/2)+O(N)

O(N*log N)

题目二 归并排序的扩展

小和问题:在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。

和排序问题的差别:

小和问题相等时拷贝右组小和

排序问题都可

public static int smallSum(int[] arr){
	if(arr==null || arr.length<2){
		return 0;
	}
	return process(arr,0,arr.length-1);
}
arr[L..R]既要排好序,也要求小和
public static int process(int[] arr,int l,int r){
	if(l==r){
		return 0;
	}
	int mid=l+((r-l)>>1);
	return process(arr,l,mid)+process(arr,mid+1,r)+merge(arr,l,mid,r);
}
public static int merge(int[] arr,int L,int m,int r){
	int[] help=new int[r-L+1];
	int i=0;
	int p1=L;
	int p2=m+1;
	int res=0;
	while (p1<=m && p2<=r){
		res+=arr[p1]<arr[p2]?(r-p2+1)*arr[p1]:0;
		help[i++]=arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
	}
	while(p1<=m){
		help[i++]=arr[p1++];
	}
	while(p2<=r){
		help[i++]=arr[p2++];
	}
	for(i=0;i<help.length;i++){
		arr[L+i]=help[i];
	}
	return res;
}

逆序对问题:在一个数组中,左边的数如果比右边的数大,则两个数构成一个逆序对,打印所有逆序对

题目六 荷兰国旗问题

  1. 给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,大于num的数放在数组右边。要求额外空间复杂度O(1),时间复杂度O(N)。
  2. 给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组中间,大于num的数放在数组右边。要求额外空间复杂度O(1),时间复杂度O(N)。

1的思路:1)[i]<=num,[i]和<=区的下一个数交换,<=区右扩,i++

2)[i]>num,i++。

2的思路:1)[i]<num,[i]和<区下一个交换,<区右扩,i++

2)[i]==num,i++

3)[i]>num.[i]和>区前一个交换,>区左扩,i原地不变。

快排1.0 【<5|>5|5】

快排2.0 [<5|==5|>5|5]

快排3.0 [<5|==5|>5|5],5是随机选的

public static void quickSort(int[] arr,int L,int R){
	if(L<R){
		swap(arr,L+(int)(Math.random()*(R-L+1)),R);
		int[] p=partition(arr,L,R);
		quickSort(arr,L,p[0]-1);//<区
		quickSort(arr,p[1]+1,R);//>区
	}
}
public static int[] partition(int[] arr,int L,int R){
	int less=L-1;//<区右边界
	int more=R;//>区左边界
	while(L<more){
		if(arr[L]<arr[R]){
			swap(arr,++less,L++);
		}else if(arr[L]>arr[R]){
			swap(arr,--more,L);
		}else{
			L++;
		}
	}
	swap(arr,more,R);
	return new int[] {less+1,more};
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值