240508.LeetCode——807.保持城市天际线

题目描述

给你一座由 n x n 个街区组成的城市,每个街区都包含一座立方体建筑。给你一个下标从 0 开始的 n x n 整数矩阵 grid ,其中 grid[r][c] 表示坐落于 r 行 c 列的建筑物的 高度 。

城市的 天际线 是从远处观察城市时,所有建筑物形成的外部轮廓。从东、南、西、北四个主要方向观测到的 天际线 可能不同。

我们被允许为 任意数量的建筑物 的高度增加 任意增量(不同建筑物的增量可能不同) 。 高度为 0 的建筑物的高度也可以增加。然而,增加的建筑物高度 不能影响 从任何主要方向观察城市得到的 天际线 。

在 不改变 从任何主要方向观测到的城市 天际线 的前提下,返回建筑物可以增加的 最大高度增量总和 。

EX1.

57521addd5cb46a69c2a1435a2a507d5.jpg

 

输入: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分钟结束战斗然后写物理的,现在看来破灭了...还有就是八点之前一直在宿舍刷推特...真的服了自己的。

       归根到底还是不能自律,有的时候还是要靠外界刺激,他律更适合我。主要今天也纠结了好久要不要买平板...最近一直在物色,感觉精力全花在这个上面了...最晚还是明天就做出决定吧,我觉得不能再浪费我的精力了...今天的收获不少,希望能坚持下去吧。我的梦想很大,只是希望不要做语言上的巨人,行动上的矮子。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值