zoukankan      html  css  js  c++  java
  • 待字闺中之相差甚远面试题分析

    题目来源,待字闺中,原创@陈利人 ,欢迎大家继续关注微信公众账号“待字闺中”

    原题

    给定一个数组,我们能够找到两个不相交的、而且是连续的子数组A和B,A中的数字和为sum(A), B中的元素和为sum(B)。找到这种A和B,满足sum(A) - sum(B)的绝对值是最大的。

    比如:[2, -1 -2, 1, -4, 2, 8]划分为A=[-1, -2, 1, -4], B=[2, 8], 最大的值为16

    分析

    假设没有比較丰富的经验。这个题目咋一看,有一种不明觉厉的感觉。但仅仅要逐层分析。就能够看到。事实上仅仅要分析两层就能够了。首先我们来看看题目有哪些要点(明白题意,有不清楚的,一定要澄清。):

    1. 子数组是不相交的

    2. 子数组是连续的,这个有点多余,但还是强调一下得好

    然后题目的要求是。差的绝对值最大。

    那我们自然而然可以想到:找到的两个不相交的子数组,一个值要非常小,一个值要非常大。

    这样才可以保证差的绝对值最大。那怎样找到这种数组呢?我们从不相交的这个条件入手。

    看题目中样例(从简单的样例出发,发现解决方式,是面试中经常使用技巧。切记!

    ):

    0    1    2    3    4    5    6
    2    -1    -2    1    4    2    8

    看上面的表格,假设两个子数组不想交。我们有六个位置,作为划分的备选。0和1之间、1和2之间、2和3之间。...。直到5和6之间。这六个位置,都能够将数组划分为两部分。我们设定。数组长度为n,i将数据划分为两部分分别为 [0,i-1]和[i,n-1]。都是两边包括的集合。i是从1到n-1的。

    对于随意的i。我们得到了两部分[0, i-1]和[i, n-1]。

    接下来,就是在这两部分中,找到一个和最小的子数组A,以及和最大的子数组B。那么A-B的绝对值,就是i这个划分下,满足条件的两个数组的差的最大值。对于。全部的i而言。这个绝对值最大时的A和B就是我们要找到的。

    思路通顺了,接下来要确定,找到在i处划分,和最大以及和最小的子数组的方法。

    这里,就要使用到,我们前几天分享的动态规划的思想。

    那篇文章,大家好好阅读分析了么。相信一定可以给大家带来非常多的启示。回到这个题目,我们单独的考虑,给定一个数组。求和最大的子数组以及和最小的子数组。

    先分析和最大的子数组,这个问题,是比較经典的问题了。可是我们这里要处理的是。求得每个i左側的最大连续子数组。

    作例如以下分析。如果数组为X, 如果max_until[i]表示,以i位置结尾的连续子数组的最大和。max_until[i]和max_until[i-1]是什么关系呢?

    1. 假设X[i] + max_until[i - 1] > max_until[i - 1] and X[i] + max_until[i- 1] > X[i]。那么X[i]应该增加到连续子数组中。max_until[i] = max_until[i-1] + X[i].

    2. 否则max_until[i] = X[i]。连续子数组仅仅有一个元素。

    可是。我们要的并非以i结尾的子数组。虽然给的样例中是这种,我们要的是i之前的全部连续子数组中,和最大的。并不一定包含i。要怎样处理呢?我们再开辟子数组max_left[i]表示[0,i]中连续子数组的最大值。那这个值要怎样求得呢?我们在遍历数组,求得max_until[i]的时候,max_left[i]仅仅须要在max_until[i]和此前保存的最大值里取最大的就可以。也就是一次遍历,就能够全然求得max_until数组和max_left数组。同理能够求得min_until以及min_left数组。

    这是处理的划分的左半部分。那么右半部分呢?右半部分的思路也是一样的,仅仅只是,我们在遍历数组的时候,须要从右向左进行遍历。方法的总体空间复杂度为O(n),时间复杂度也是O(n)。

    详细代码例如以下:

    void subArrFromLeft(vector<int>& data,vector<int>& maxVec,vector<int>& minVec)
    {
    	int i,length = data.size();
    	if(length == 0)return;
    	vector<int> dpMax(length);
    	vector<int> dpMin(length);
    	dpMax[0] = dpMin[0] = maxVec[0] = minVec[0] = data[0];//初始化
    	for(i=1;i<length;i++)
    	{
    		dpMax[i] = max(dpMax[i-1]+data[i],data[i]);
    		maxVec[i] = max(maxVec[i-1],dpMax[i]);
    		dpMin[i] = min(dpMin[i-1]+data[i],data[i]);
    		minVec[i] = min(minVec[i-1],dpMin[i]);
    	}
    }
    void subArrFromRight(vector<int>& data,vector<int>& maxVec,vector<int>& minVec)
    {
    	int i,length = data.size();
    	if(length == 0)return;
    	vector<int> dpMax(length);
    	vector<int> dpMin(length);
    	dpMax[length-1] = dpMin[length-1] = maxVec[length-1] = minVec[length-1] = data[length-1];
    	for(i=length-2;i>=0;i--)
    	{
    		dpMax[i] = max(dpMax[i+1]+data[i],data[i]);
    		maxVec[i] = max(maxVec[i+1],dpMax[i]);
    		dpMin[i] = min(dpMin[i+1]+data[i],data[i]);
    		minVec[i] = min(minVec[i+1],dpMin[i]);
    	}
    }
    int farMost(vector<int>& data)//程序入口
    {
    	int length = data.size();
    	vector<int> max_left(length);
    	vector<int> min_left(length);
    	vector<int> max_right(length);
    	vector<int> min_right(length);
    	subArrFromLeft(data,max_left,min_left);//从左到右遍历
    	subArrFromRight(data,max_right,min_right);//从右到左遍历
    	int i,res = 0;
    	for(i=1;i<length;i++)//遍历每个切割位置
    	{
    		int tmp = abs(max_left[i-1]-min_right[i]);
    		if(tmp > res ) res = tmp;
    		tmp = abs(min_left[i-1]-max_right[i]);
    		if(tmp > res ) res = tmp;
    	}
    	return res;
    }


  • 相关阅读:
    Auto.js常用控件整理
    python对接口sign签名操作
    # 859.亲密字符串
    linux系统如何挂载FTP共享文件
    解决“Tomcat控制台输出乱码问题”
    关于“Unknown or unsupported command 'install'”问题解决的小结
    输出九九乘法表
    python webdriver混合驱动测试框架(数据驱动+关键字驱动)
    python webdriver关键字框架
    python webdriver测试框架--数据驱动DB驱动
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7301127.html
Copyright © 2011-2022 走看看