牛客网(算法思维锻炼)

已知一个整型数组arr,数组长度为size且size大于2,arr有size-1种可以划分成左右两部分的方案。
比如:
arr = {3, 2, 3, 4, 1, 2}
第1种划分左部分为[3],右部分为[2, 3, 4, 1, 2]
第2种划分左部分为[3, 2],右部分为[3, 4, 1, 2]
第3种划分左部分为[3, 2, 3],右部分为[4, 1, 2]
第4种划分左部分为[3, 2, 3, 4],右部分为[1, 2]
第5种划分左部分为[3, 2, 3, 4, 1],右部分为[2]
每一种划分下,左部分都有最大值记为max_left,右部分都有最大值记为max_right。
求|max_left-max_right|(左部分最大值与左部分最大值之差的绝对值),最大是多少?
要求:时间复杂度为O(N),额外空间复杂度O(1)

1.暴力解法

 
public static void main(String[] args) { // TODO Auto-generated method stub int[] arr = {3, 2, 3, 4, 1, 2}; int len = arr.length; int max = Integer.MIN_VALUE; for(int k=1;k<len-1;k++){//k就像是数组里面的一把刀 i的右边为右边区域 int left = Integer.MIN_VALUE; for(int i=0;i<=k;i++){//左边区域的最大值 left = Math.max(left,arr[i]); } int right = Integer.MIN_VALUE; for(int j=len-1;j>k;j--){//右边区域的最大值 right = Math.max(right,arr[j]); } max = Math.max(max,Math.abs(left-right)); } System.out.println(max); }
这个题读懂后不过是求左边区域的最大值减去右边区域的最大值 中的绝对值最大值,暴力遍历,左边范围,和右边范围,进行比较

2.使用辅助数组

	public static void planFunction(int[] arr){
		int[] larr = new int[arr.length];
		int[] rarr = new int[arr.length];
		larr[0]=arr[0];
		rarr[arr.length-1]=arr[arr.length-1];
		for(int i=1;i<arr.length;i++){//提前计算好左边范围的最大值
			if(arr[i]>larr[i-1]){
				larr[i]=arr[i];
			}else{
				larr[i]=larr[i-1];
			}
		}
		for(int i=arr.length-2;i>=0;i--){//提前计算好右边范围的最大值
			if(arr[i]>rarr[i+1]){
				rarr[i]=arr[i];
			}else{
				rarr[i]=rarr[i+1];
			}
		}
		int max = Integer.MIN_VALUE;
		for(int i=0;i<arr.length;i++){
			max = Math.max(max,Math.abs(larr[i]-rarr[i]));
		}
		System.out.println(max);
	}
使用辅助数组记录左边不同范围最大值,和右边不同范围最大值:
如:
int[] arr = {1,2,5,8,0,-5,1}; //原来的数组
//记录左边不同范围的最大值 0-0范围最大值为1、0-1范围最大值为2、0-2最大值为5、0-3最大值为5、0-4最大值为8、0-5最大值为8、0-6最大值为8
int[] larr={1,2,5,8,8,8,8};
//记录右边不同范围的最大值 6-6范围最大值为1、6-5范围最大值为1、6-4最大值为1、6-3最大值为8、6-2最大值为8、6-1最大值为8、6-0最大值为8
int[] rarr={8,8,8,8,1,1,1};
这样一来就可以直接对不同范围的最大值进行筛选,筛选出最大值。
 

3.最优解

 public static void MaxABS3(int A[]){
		int max=Integer.MIN_VALUE;
		for(int i=0;i<A.length;i++){
			max = Math.max(A[i],max);
		}
		
		//最大值
		// 左范围最小值 - 右范围最大值
		// 左范围最大值 - 右范围最大值
		int numMax=max-Math.min(A[0],A[A.length-1]);
		System.out.println(numMax);
	}public static void MaxABS3(int A[]){
		int max=Integer.MIN_VALUE;
		for(int i=0;i<A.length;i++){
			max = Math.max(A[i],max);
		}
		
		//最大值
		// 左范围最小值 - 右范围最大值
		// 左范围最大值 - 右范围最大值
		int numMax=max-Math.min(A[0],A[A.length-1]);
		System.out.println(numMax);
	}
首先思考:
求绝对值最大值:
// 左边范围中的最大值中最小的值 - 右边范围最大值
// 左边范围中的最大值中最大的值 - 右边范围最大值

这个问题是求左边范围的最大值减去右边范围的最大值  中  求绝对值最大的那个数
什么情况下绝对值最大???

一个很小的数减去一个很大的数
一个很大的数减去一个很小的数

左边范围怎么样划分得到的最大值是最小的?

arr[0]就是最小的
 
因为向右遍历只有遇见比arr[0]大的数才会替换max
所以越遍历只能使max越大
 

右边范围怎么样划分得到的最大值是最小的?

同理:
arr[6]就是最小的
 
因为向左遍历只有遇见比arr[0]大的数才会替换max
所以越遍历只能使max越大

找到数组中的最大值

遍历这个值就是相当于找到 左边范围或者右边所有范围中的最大值
 
代码中的
int numMax=max-Math.min(A[0],A[A.length-1]);
就相当于 如果 左边范围的值小那么最终结果就是
// 左边范围中的最大值中最小的值 - 右边范围最大值
 如果 右边 范围的值小那么最终结果就是
// 左边范围中的最大值中最大的值 - 右边范围最大值
那个最大值无论从左找还是从右找 都是相当于在找数组中的最大值
 
 
此时:
 
左边范围或者右边所有范围中的最大值  减去 左边范围划分或者右边范围划分中最所有最大值 最小的那个值
 

.....写的理解如果有点不对,希望大佬指正

 
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] arr = {99, 2, 3, 4, 1, 2};
		
		int[] test = new int[2];//0 左边最大值 右边最大值
		
		int len = arr.length;
		int max = Integer.MIN_VALUE;
		for(int k=1;k<len-1;k++){//k就像是数组里面的一把刀 i的右边为右边区域
			
			int left = Integer.MIN_VALUE;
			for(int i=0;i<=k;i++){//左边区域的最大值
				left = Math.max(left,arr[i]);
			}
			
			int right = Integer.MIN_VALUE;
			for(int j=len-1;j>k;j--){//右边区域的最大值
				right = Math.max(right,arr[j]);
			}			
			if(Math.abs(left-right)>max){
				max =Math.abs(left-right);
				
				test[0]=left;//记录下最终结果的左边最大值 和右边最大值
				test[1]=right;
			}
			
		}
		
		System.out.println(max);
		System.out.println(test[0]);
		System.out.println(test[1]);
		
	}
修改了代码一帮助理解代码3
 
 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SUNbrightness

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值