已知一个整型数组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