题目描述
给你一座由 n x n
个街区组成的城市,每个街区都包含一座立方体建筑。给你一个下标从 0 开始的 n x n
整数矩阵 grid
,其中 grid[r][c]
表示坐落于 r
行 c
列的建筑物的 高度 。
城市的 天际线 是从远处观察城市时,所有建筑物形成的外部轮廓。从东、南、西、北四个主要方向观测到的 天际线 可能不同。
我们被允许为 任意数量的建筑物 的高度增加 任意增量(不同建筑物的增量可能不同) 。 高度为 0
的建筑物的高度也可以增加。然而,增加的建筑物高度 不能影响 从任何主要方向观察城市得到的 天际线 。
在 不改变 从任何主要方向观测到的城市 天际线 的前提下,返回建筑物可以增加的 最大高度增量总和 。
EX1.
输入:grid = [[3,0,8,4],[2,4,5,7],[9,2,6,3],[0,3,1,0]] 输出:35 解释:建筑物的高度如上图中心所示。 用红色绘制从不同方向观看得到的天际线。 在不影响天际线的情况下,增加建筑物的高度: gridNew = [ [8, 4, 8, 7], [7, 4, 7, 7], [9, 4, 8, 7], [3, 3, 3, 3] ]
EX2.
输入:grid = [[0,0,0],[0,0,0],[0,0,0]] 输出:0 解释:增加任何建筑物的高度都会导致天际线的变化。
提示
n == grid.length
n == grid[r].length
2 <= n <= 50
0 <= grid[r][c] <= 100
代码实现
C语言
int min_function(int x,int y)//定义求解两个给定数中较小值的函数
{
if(x<y)
{
return x;
}
else
{
return y;
}
}
int maxIncreaseKeepingSkyline(int** grid, int gridSize, int* gridColSize)
{
int i;
int j;//定义循环变量
int sum=0;//定义函数返回值:增加的天际线总和
int *grid_r=(int*)malloc(gridSize*sizeof(int));
int *grid_c=(int*)malloc(gridSize*sizeof(int));//动态规划:根据给定参数动态分配内存创建数组(一维)
memset(grid_r,0,sizeof(int)*gridSize);
memset(grid_c,0,sizeof(int)*gridSize);//动态数组的初始化方法:卡了好久...后面再说
for(i=0;i<gridSize;i++)
{
for(j=0;j<gridSize;j++)//二重循环遍历二维数组
{
if(grid[i][j]>grid_r[i])//若当前值大于行最值,存下来
{
grid_r[i]=grid[i][j];
}
if(grid[i][j]>grid_c[j])//若当前值大于列最值,存下来
{
grid_c[j]=grid[i][j];
}
}
}
for(i=0;i<gridSize;i++)
{
for(j=0;j<gridSize;j++)//二重循环遍历数组
{
sum=sum+min_function(grid_r[i],grid_c[j])-grid[i][j];//计算每个值与所在行/列的最大值中较小值的差值(有点绕...但会者不难)
}
}
free(grid_r);
free(grid_c);//千万别忘记数组是前面动态分配的,需要清空内存!!!
return sum;//返回增加的数值
}
思路
第一眼看到题目就想到了,要记录下行/列的最值,其实东西看过去是一样的,南北看过去是一样的,所以只需要两个变量就可以了,就是行和列。行列数未知,于是使用动态内存分配,二重循环遍历二维数组这个不用说了。我被卡住的地方主要有两个,第一个是刚开始分配的数组如何初始化?我首先尝试了一下静态数组的方法:
grid_r={0};
grid_c={0};
但貌似编译不通过。后面我查了原因是语法错误,这样应该是在定义的时候赋值的,就是应该用:
int arr[5]={0};
而不是像现在这样,先定义了再赋值。
后面换一个思路,在二重循环中第二轮循环开始时假设最大值为第一个元素:
for(i=0;i<gridSize;i++)
{
grid_r[i]=grid[i][0];
for(j=1;j<gridColSize[0];j++)
{
if(grid[i][j]>grid_r[i])
{
grid_r[i]=grid[i][j];
}
}
}
编译可以通过,但是测试样例输出数值不对,这一点我有点疑惑...于是抱着疑惑心理打开了题解...最后看到了大佬的思路:
memset(grid_r,0,gridSize*sizeof(int));
memset(grid_r,0,gridSize*sizeof(int));
???根本没见过?打开AI,打开百度搜索得到答案:
void *memset(void *s, int ch, size_t n);
函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法
原来是这样,这里的用法是将grid_r/grid_c中当前位置后面的gridSize*sizeof(int))个字节用0替换并返回grid_r/grid_c。又学到了新的函数!用于数据结构的初始化,抱着学习的心态我又找到了另一种用于初始化动态数组的方法:
使用循环:
int *arr = NULL;
int i, n = 5;
arr = (int *)malloc(n * sizeof(int));
for(i = 0; i < n; i++)
{
arr[i] = i;
}
这个问题就研究到这里。我遇到的第二个卡我的地方是后面的计算增加值,还是几个思路:
第一个:用一个新的数组记录增加后的二维数组,然后再遍历两个数组,对应值相减,我认为可行(我没敲)。
第二个:也就是我现在的思路,就是计算每个位置可增加的数,不做记录,最后相加返回(成功实现)。
这个地方主要是思路问题,但其实方法很多,不算难点,难点还是前面的。
总结
写到这...已经是晚上10:01了,我是8:10开始写的,中间玩了近40分钟手机吧...还是被自己的不自律笑到了,原本说只花30分钟结束战斗然后写物理的,现在看来破灭了...还有就是八点之前一直在宿舍刷推特...真的服了自己的。
归根到底还是不能自律,有的时候还是要靠外界刺激,他律更适合我。主要今天也纠结了好久要不要买平板...最近一直在物色,感觉精力全花在这个上面了...最晚还是明天就做出决定吧,我觉得不能再浪费我的精力了...今天的收获不少,希望能坚持下去吧。我的梦想很大,只是希望不要做语言上的巨人,行动上的矮子。