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;
    }


  • 相关阅读:
    ArrayList用法
    MessageBox
    将文本文件导入Sql数据库
    在桌面和菜单中添加快捷方式
    泡沫排序
    Making use of localized variables in javascript.
    Remove double empty lines in Visual Studio 2012
    Using Operations Manager Connectors
    Clear SharePoint Designer cache
    Programmatically set navigation settings in SharePoint 2013
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7301127.html
Copyright © 2011-2022 走看看