左神算法课堂系列--数组划分最大绝对值之差问题

算法思维的锻炼

【题目】
已知一个整型数组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,3,2,5,4,6,转化之后是1,3,3,5,5,6,从右到左的记录最大值同理,就是利用了这个数组来省去了每一次都要在左边右边找到最大值的时间。第三种就神了,我是真的佩服,假设划分位置是i,那么无论最大值在左边还是右边都一定用得着的,假设就在右边,那么左边的的数一定有第一个数, 并且,最小一定不会比第一个数小(因为左边的数一定存在!)。可能最神的这种方法不那么好理解,仔细看看我上面仅有的解析两句哈哈,事实上就是这样 的了

public class Code_02_MaxABSBetweenLeftAndRight {

	//时间复杂度是O(N^2)的暴力法,分别找出第i个位置的左边的最大值,右边的最大值
	public static int maxABS1(int[] arr) {
		int res = Integer.MIN_VALUE;
		int maxLeft = 0;
		int maxRight = 0;
		for (int i = 0; i != arr.length - 1; i++) {
			maxLeft = Integer.MIN_VALUE;
			for (int j = 0; j != i + 1; j++) {
				maxLeft = Math.max(arr[j], maxLeft);
			}
			maxRight = Integer.MIN_VALUE;
			for (int j = i + 1; j != arr.length; j++) {
				maxRight = Math.max(arr[j], maxRight);
			}
			res = Math.max(Math.abs(maxLeft - maxRight), res);
		}
		return res;
	}

	//时间复杂度是O(N) 空间复杂度是O(N)
	public static int maxABS2(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++) {
			lArr[i] = Math.max(lArr[i - 1], arr[i]);
		}
		for (int i = arr.length - 2; i > -1; i--) {
			rArr[i] = Math.max(rArr[i + 1], arr[i]);
		}
		int max = 0;
		for (int i = 0; i < arr.length - 1; i++) {
			max = Math.max(max, Math.abs(lArr[i] - rArr[i + 1]));
		}
		return max;
	}

	//最优解,时间复杂度是O(N) 空间复杂度是O(1)
	public static int maxABS3(int[] arr) {
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < arr.length; i++) {
			max = Math.max(arr[i], max);
		}
		return max - Math.min(arr[0], arr[arr.length - 1]);
	}

	//产生随机数组
	public static int[] generateRandomArray(int length) {
		int[] arr = new int[length];
		for (int i = 0; i != arr.length; i++) {
			arr[i] = (int) (Math.random() * 1000) - 499;
		}
		return arr;
	}

	public static void main(String[] args) {
		int[] arr = generateRandomArray(200);
		System.out.println(maxABS1(arr));
		System.out.println(maxABS2(arr));
		System.out.println(maxABS3(arr));
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值