1. 程式人生 > >2014騰訊實習生招聘陣列牆演算法

2014騰訊實習生招聘陣列牆演算法

題目:隨機給定一個整型陣列,每個陣列中的數字代表陣列所在位置牆的高度,問這個陣列所能拼湊的最大矩形牆的面積為多少。

例如,如下圖示,陣列{2, 1, 6, 5, 4, 7, 2}所能拼湊出的最大矩形為{6, 5, 4, 7}上所組成的高度為4的牆(淺藍色部分),其面積為4*4 = 16.


演算法分析:首先把最初的陣列source備份到backup陣列中,另外新建maxnum陣列,儲存每個元素所在的最大的矩形的面積值,初始值置0。從backup陣列開始,找出整個陣列中最小的元素,backup陣列中所有的元素都減去這個元素,將陣列按0元素進行切割成子的新陣列,計算陣列的長度與新生成矩形的高度,求出新的最大矩形面積值並與maxnum中儲存的數值進行比較,如果大則更新。演算法複雜度為O(n).

具體如下:

1.備份source到backup,新建maxnum並置0。

2.按0元素切割陣列,如果能得到有效子陣列,將子陣列中的最小元素求出,更新backup陣列與maxnum陣列。

3.重複2直到按0元素切割不能獲得有效子陣列。

4.繼續處理下一段2中所得到的有效子陣列。

流程圖如下圖示:

以示例圖為例,整個流程的陣列變換過程如下各圖所示:

最後可以在max中得到各個元素所在的最大矩形的面積。

JAVA實現的程式碼如下:

import java.util.Random;


public class Find_max_Rectangle {


public static void main(String[] args) {
// TODO Auto-generated method stub
int[] source = new int[20];
createRandomA(source);
printA(source);
int[] backup = new int[source.length];
int[] maxnum = new int[source.length];
for(int i = 0; i < source.length; i ++){
backup[i] = source[i];
maxnum[i] = 0;
}
findmax(source, backup, maxnum, new int[]{0, source.length - 1, 0, source.length - 1});
System.out.println();


int max = 0;
for(int i = 0; i < maxnum.length; i ++){
max = max > maxnum[i] ? max : maxnum[i];
System.out.print(maxnum[i] + " ");
}
System.out.println();
System.out.println(max);
}


private static void printA(int[] source) {
// TODO Auto-generated method stub
for(int i = 0; i < source.length; i ++)
System.out.print(source[i] + " ");
}


private static int findmax(int[] source, int[] backup, int[] maxnum, int[] tag) {
// TODO Auto-generated method stub

while(get_cutoff_backup(backup, tag)){

int tmp = backup[tag[2]];

for(int i = tag[2]; i <= tag[3]; i ++) {
tmp = tmp < backup[i] ? tmp : backup[i];
}

for(int i = tag[2]; i <= tag[3]; i ++) backup[i] -= tmp;

if(tag[3] >= tag[2] && maxnum[tag[2]] < (tag[3] - tag[2] + 1) * (source[tag[2]] - backup[tag[2]])){
for(int i = tag[2]; i <= tag[3]; i ++) 
maxnum[i] = (tag[3] - tag[2] + 1) * (source[i] - backup[i]);
findmax(source, backup, maxnum, new int[]{tag[2], tag[3], tag[2], tag[3]});
}

tag[0] = tag[2] + 1;
if(tag[0] > tag[1]) break;
}
return -1;
}


private static boolean get_cutoff_backup(int[] backup, int[] tag) {
// TODO Auto-generated method stub

boolean have_a_sub_head = false;
for(int i = tag[0]; i <= tag[1]; i ++){
if(!have_a_sub_head && backup[i] != 0) {tag[2] = i; have_a_sub_head = true;}
if(have_a_sub_head && backup[i] == 0) {tag[3] = i - 1; return true;}
if(have_a_sub_head && i == tag[1] && backup[i] != 0) {tag[3] = i; return true;}
}
return false;
}


private static void createRandomA(int[] a) {
// TODO Auto-generated method stub
Random random = new Random();
for(int i = 0; i < a.length; i ++)
a[i] = random.nextInt(30);
}


}