【面试题】连续子数组乘积最大值与柱状图中找最大矩形
2013-10-10 23:51
489 查看
连续子数组求和最大值比较常见,乘积与求和有相通之处。10月9号美团的笔试考到了这题。
第一题:原题
给一个浮点数序列,求连续子串乘积的最大值,例如 -2.5,4,0,3,0.5,8,-1,则取出的最大乘积连续子串为3,0.5,8。也就是说,上述数组中,3 0.5 8这3个数的乘积3*0.5*8=12是最大的,而且是连续的。
解法一:
用动态规划很好做。问题的关键是,序列中有正数也有负数,所以,需要记录最大值,也要记录最小值。
解法二:
也可以扫一遍序列做出来,不过也要记录最大值和最小值,以及当前的最大值和最小值,当当前的最大值小于1的时候,设置为当前的序列值,呃,感觉语言有点绕,+_+,可以看《剑指offer》面试题31:连续子数组的最大和,类比一下就行了。还是用代码说话吧,逻辑会比较清楚。
两个解法的时间复杂度都是O(1),解法一的空间复杂度是O(n),解法二的空间复杂度也是O(1)。其实解法一的空间复杂度也可以降为O(1),不用数组,用四个变量即可。
第二题:原题
在柱状图中找最大的矩形:给一组非负的整数来表示一个柱状图,设计一个算法找到最大面积的能适合到柱状图内的矩形。比如,对于这组数,1 2 3 4 1 ,有两种可能的方案,一种是适合到 2 3 4 内的矩形,面积是 2*3;另一种是适合到 3 4 内的矩形,面积是 3*2。
用数学点的描述就是,找所给数组的一个连续子数组,使该子数组的最小值与数组长度乘积最大。
解法是在待字闺中微信公众账号里面看到的,一个线性算法是用堆栈来保存当前可能的矩形(高度和起始位置)。从左到右扫描,对一个元素,如果
a)大于栈顶元素, push;
b)小于的话,pop所有的大于它的元素,计算面积,更新最大值。这时如果堆栈空,push一个新的元素,高度等于当前元素,起始位置为0;否则,push当前元素高度和栈顶的起始位置。
比如1 3 2 2 3这个数组,操作如下:
代码如下:
扩展问题是:
在一个位图中找面积最大的白色矩形:给你一个NxN的黑白位图,找一个面积最大的全白色的矩形。注意了,是一个矩形,不是任意一个白色相连的区域。
可以生成一个新的矩阵C,C[i][j]表示第j列,从第i个元素开始,包括第i个元素,向上数,直到遇到0时,1的个数。然后再每一行按一维做就可以了。
第一题:原题
给一个浮点数序列,求连续子串乘积的最大值,例如 -2.5,4,0,3,0.5,8,-1,则取出的最大乘积连续子串为3,0.5,8。也就是说,上述数组中,3 0.5 8这3个数的乘积3*0.5*8=12是最大的,而且是连续的。
解法一:
用动态规划很好做。问题的关键是,序列中有正数也有负数,所以,需要记录最大值,也要记录最小值。
double MaxMul(double *num, int len) { if(num == NULL || len < 1) return 0; double *maxMul = new double[len]; double *minMul = new double[len]; maxMul[0] = num[0]; minMul[0] = num[0]; double maxM = num[0]; for(int i = 1; i < len; ++i) { maxMul[i] = maxMul[i-1]*num[i] > num[i] ? maxMul[i-1]*num[i] : num[i]; maxMul[i] = maxMul[i] > minMul[i-1]*num[i] ? maxMul[i] : minMul[i-1]*num[i]; minMul[i] = minMul[i-1]*num[i] < num[i] ? minMul[i-1]*num[i] : num[i]; minMul[i] = minMul[i] < maxMul[i-1]*num[i] ? minMul[i] : maxMul[i-1]*num[i]; maxM = maxM > maxMul[i] ? maxM : maxMul[i]; } delete[] maxMul; delete[] minMul; return maxM; }
解法二:
也可以扫一遍序列做出来,不过也要记录最大值和最小值,以及当前的最大值和最小值,当当前的最大值小于1的时候,设置为当前的序列值,呃,感觉语言有点绕,+_+,可以看《剑指offer》面试题31:连续子数组的最大和,类比一下就行了。还是用代码说话吧,逻辑会比较清楚。
double MaxMul2(double *num, int len) { if(num == NULL || len < 1) return 0; double maxM = num[0]; double maxMul = num[0]; double minMul = num[0]; double maxCur = num[0]; double minCur = num[0]; for(int i = 1; i < len; ++i) { if(maxCur < 1) maxCur = num[i]; else maxCur *= num[i]; minCur *= num[i]; if(maxCur < minCur) { double tmp = maxCur; maxCur = minCur; minCur = tmp; } maxMul = maxMul > maxCur ? maxMul : maxCur; minMul = minMul < minCur ? minMul : minCur; } return maxMul; }
两个解法的时间复杂度都是O(1),解法一的空间复杂度是O(n),解法二的空间复杂度也是O(1)。其实解法一的空间复杂度也可以降为O(1),不用数组,用四个变量即可。
第二题:原题
在柱状图中找最大的矩形:给一组非负的整数来表示一个柱状图,设计一个算法找到最大面积的能适合到柱状图内的矩形。比如,对于这组数,1 2 3 4 1 ,有两种可能的方案,一种是适合到 2 3 4 内的矩形,面积是 2*3;另一种是适合到 3 4 内的矩形,面积是 3*2。
用数学点的描述就是,找所给数组的一个连续子数组,使该子数组的最小值与数组长度乘积最大。
解法是在待字闺中微信公众账号里面看到的,一个线性算法是用堆栈来保存当前可能的矩形(高度和起始位置)。从左到右扫描,对一个元素,如果
a)大于栈顶元素, push;
b)小于的话,pop所有的大于它的元素,计算面积,更新最大值。这时如果堆栈空,push一个新的元素,高度等于当前元素,起始位置为0;否则,push当前元素高度和栈顶的起始位置。
比如1 3 2 2 3这个数组,操作如下:
i | C[i] | 栈操作 | 最大值 | 栈内容 |
0 | 1 | push (1,0) | (1,0) | |
1 | 3 | push (3,1) | (3,1)(1,0) | |
2 | 2 | pop (3,1),push (2,1) | (2-1)*3=3 | (2,1)(1,0) |
3 | 2 | 什么都不做 | (2,1)(1,0) | |
4 | 3 | push(3,4) | (3,4)(2,1)(1,0) | |
5 | 0 | pop(3,4) | (5-4)*3=3 | (2,1)(1,0) |
5 | 0 | pop(2,1) | (5-1)*2=8 | (1,0) |
5 | 0 | pop(1,0) | (5-0)*1=5 |
int MaxArea(int *num, int len) { if(num == NULL || len < 1) return 0; stack<int> numStack; stack<int> indStack; numStack.push(num[0]); indStack.push(0); int lastPopInd = 0; int maxMul = num[0]; for(int i = 1; i < len; ++i) { if(num[i] > numStack.top()) { numStack.push(num[i]); indStack.push(i); } else if(num[i] < numStack.top()) { while(!numStack.empty() && num[i] < numStack.top()) { int numPop = numStack.top(); lastPopInd = indStack.top(); maxMul = (numPop * (i - lastPopInd)) > maxMul ? (numPop * (i - lastPopInd)) : maxMul; numStack.pop(); indStack.pop(); } if(numStack.empty() || num[i] > numStack.top()) { numStack.push(num[i]); indStack.push(lastPopInd); } } } while(!numStack.empty()) { int numPop = numStack.top(); lastPopInd = indStack.top(); maxMul = (numPop * (len - lastPopInd)) > maxMul ? (numPop * (len - lastPopInd)) : maxMul; numStack.pop(); indStack.pop(); } return maxMul; }
扩展问题是:
在一个位图中找面积最大的白色矩形:给你一个NxN的黑白位图,找一个面积最大的全白色的矩形。注意了,是一个矩形,不是任意一个白色相连的区域。
可以生成一个新的矩阵C,C[i][j]表示第j列,从第i个元素开始,包括第i个元素,向上数,直到遇到0时,1的个数。然后再每一行按一维做就可以了。
相关文章推荐
- 想成为嵌入式程序员应知道的0×10个基本问题
- 秋,程序员在路上
- 秋,程序员在路上
- 阿里面试题型总结
- 黑马程序员 ---java基础加强01
- 输出每个元素,在它左侧且比它小的最近元素
- 黑马程序员-------.net基础知识六
- 架构师面试【1】
- 怎么面试一个10年以上经验的架构师?
- IT行业岗位以及发展方向(职业规划迷茫的欢迎查看)
- [剑指offer][面试题07-扩展]用两个队列实现栈
- 说说我来北京面试的几次遭遇经历。
- 笔试面试中常见的位运算用法
- 黑马程序员--高新技术
- 黑马程序员_IO流_3
- 送给程序员:最好的编程名言
- 程序员的谎谬之言还是至理名言?
- 嵌入式和驱动开发面试笔试题搜集整理
- Visual Studio程序员箴言(奋斗的小鸟)_PDF 电子书
- 笔试面试中常见的位运算用法