原帖地址
http://bbs.youkuaiyun.com/topics/390712018
问题
新的题目又来了,这次还是有关矩阵的。
一个二维数组,向这样。把它想象成一个方格一个方格,数字代表了方格的高度。然后往这些方格里倒水。
当那么高度最低的肯定就可以存住水,问一个m*n的矩阵总共能存多少水。
拿这个矩阵举例子。能存水的肯定就是高度为0的2个点,而他们只能存单位为3的水。因为超过3就是边上的那个3冒出去了。
这个能理解吧。最短板的高度就是存水的高度。这次是只受上下左右4个方格的影响。所以这个矩阵能存水的数量是3+3=6.
9 9 9 9
3 0 0 9
7 8 9 6
再举个例子,这个矩阵能存水的数量就是1.因为只有2的上下左右是3,那么2这个点只能存1个单位的水。
11111
11311
13231
11311
算法就是给定任意m*n的矩阵,计算能存多少水。
代码实现
import java.util.ArrayList;
import java.util.List;
public class T3 {
static int[][] array = {
{ 9, 9, 9, 9, 9, 10 },
{ 9, 2, 2, 3, 11, 11 },
{ 7, 2, 9, 12, 1, 20 },
{ 7, 6, 3, 1, 11, 13 },
{ 9, 9, 6, 9, 9, 14 } };
static int height = array.length;
static int width = array[0].length;// 数组宽
static int sum = 0;// 总存储水的量
public static void main(String[] a) throws Exception {
int min = 10;
int max = 10;
int[][] array2 = new int[height][width];
System.out.println("开始矩阵");
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
array2[i][j]=array[i][j];
System.out.print(array[i][j]);
if (array[i][j] < 10) {
System.out.print(" ,");
} else {
System.out.print(",");
}
}
System.out.println();
}
for (int i = 1; i < array.length - 1; i++) {// 寻找最低点
for (int j = 1; j < array[i].length - 1; j++) {
if (array[i][j] < min) {
min = array[i][j];
}
if (array[i][j] > max) {
max = array[i][j];
}
}
}
for (int i = min; i < max; i++) {
dosum(i);
}
System.out.println("结束矩阵");
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j]);
if (array[i][j] < 10) {
System.out.print(" ,");
} else {
System.out.print(",");
}
}
System.out.println();
}
System.out.println("节点加水数情况");
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j]-array2[i][j]);
if (array[i][j]-array2[i][j] < 10) {
System.out.print(" ,");
} else {
System.out.print(",");
}
}
System.out.println();
}
System.out.println("总共可以存水:" + sum);
}
//根据水位点找当前可以加水的点
public static List<List<int[]>> getMin(int shuiwei) {
List<List<int[]>> area = new ArrayList<List<int[]>>();// 区域
for (int i = 1; i < array.length - 1; i++) {// 将最小的点加入到数组中作为起始计算的点
for (int j = 1; j < array[i].length - 1; j++) {
if (array[i][j] == shuiwei) {
int[] point = { i, j };
boolean flag = true;
for (int k = 0; k < area.size(); k++) {
List<int[]> pointList = area.get(k);
if (contains(pointList, point)) {
flag = false;
break;
}
}
if (flag) {
List<int[]> pointList = new ArrayList<int[]>();
pointList.add(point);
found(shuiwei, pointList, pointList);
area.add(pointList);
}
}
}
}
return area;
}
//从一个点出发,查找周边的区域,且区域不包含最外层的点
public static void found(int shuiwei, List<int[]> pointList,
List<int[]> allPointList) {
List<int[]> pointList2 = new ArrayList<int[]>();
for (int i = 0; i < pointList.size(); i++) {
int[] point = pointList.get(i);
if(point[0]+1<height-1 && array[point[0]+1][point[1]]==shuiwei){
int[] point2 = {point[0]+1,point[1]};
if(!contains(allPointList, point2)){
pointList2.add(point2);
allPointList.add(point2);
}
}
if(point[0]-1>0 && array[point[0]-1][point[1]]==shuiwei){
int[] point2 = {point[0]-1,point[1]};
if(!contains(allPointList, point2)){
pointList2.add(point2);
allPointList.add(point2);
}
}
if(point[1]+1<width-1 && array[point[0]][point[1]+1]==shuiwei){
int[] point2 = {point[0],point[1]+1};
if(!contains(allPointList, point2)){
pointList2.add(point2);
allPointList.add(point2);
}
}
if(point[1]-1>0 && array[point[0]][point[1]-1]==shuiwei){
int[] point2 = {point[0],point[1]-1};
if(!contains(allPointList, point2)){
pointList2.add(point2);
allPointList.add(point2);
}
}
}
if(pointList2.size()>0){
found(shuiwei, pointList2, allPointList);
}else{
return;
}
}
//做加水的运算
public static void dosum(int shuiwei) {
List<List<int[]>> list = getMin(shuiwei);
List<List<int[]>> areaList = new ArrayList<List<int[]>>();// 保存新区域
for (int i = 0; i < list.size(); i++) {// 循环区域
List<int[]> pointList = new ArrayList<int[]>();// 保存新点
List<int[]> roundList = new ArrayList<int[]>();// 周边的点
for (int j = 0; j < list.get(i).size(); j++) {// 循环一个区域里的所有点。
int[] point = list.get(i).get(j);// 最低点
int[] pointTop = { point[0] - 1, point[1] };
int[] pointLeft = { point[0], point[1] - 1 };
int[] pointRight = { point[0], point[1] + 1 };
int[] pointBottom = { point[0] + 1, point[1] };
if (pointTop[0]>=0 && !contains(list.get(i), pointTop)) {// 将周边点加入,周边的点可以包括最外层的点
roundList.add(pointTop);
}
if (pointLeft[1]>=0 && !contains(list.get(i), pointLeft)) {
roundList.add(pointLeft);
}
if (pointRight[1]<width && !contains(list.get(i), pointRight)) {
roundList.add(pointRight);
}
if (pointBottom[0]<height && !contains(list.get(i), pointBottom)) {
roundList.add(pointBottom);
}
}
boolean flag = true;// 看周边的点是不是比区域里的点小
for (int j = 0; j < roundList.size(); j++) {
int[] round = roundList.get(j);
if (array[round[0]][round[1]] <= shuiwei) {
flag = false;
break;
}
}
if (flag) {// 周边点比区域所有点都大的时候,区域内所有点可以+1
for (int j = 0; j < list.get(i).size(); j++) {// 循环一个区域里的所有点。
int[] point = list.get(i).get(j);// 区域内的点
array[point[0]][point[1]] += 1;
sum += 1;
pointList.add(point);
}
if (pointList.size() > 0) {
areaList.add(pointList);
}
}
}
}
//判断数组是否包含点
public static boolean contains(List<int[]> pointList, int[] point) {
for (int i = 0; i < pointList.size(); i++) {
if (pointList.get(i)[0] == point[0]
&& pointList.get(i)[1] == point[1]) {
return true;
}
}
return false;
}
}