共计 3220 个字符,预计需要花费 9 分钟才能阅读完成。
这是我第一次打卡,目的就是希望自己一直保持学习的状态,每天都了解一些新的技术;同时这也是我第一篇博客,写得不好还请见谅!
1.Algorithm 做一个 leetcode 的算法题
542.01 Matrix
Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell.
The distance between two adjacent cells is 1.
Example 1:
Input:
[[0,0,0],
[0,1,0],
[0,0,0]]
Output:
[[0,0,0],
[0,1,0],
[0,0,0]]
Example 2:
Input:
[[0,0,0],
[0,1,0],
[1,1,1]]
Output:
[[0,0,0],
[0,1,0],
[1,2,1]]
解答:首先很容易就想到 DP,dist[i,j]=min(dist[i-1,j]+1, disti+1+1, disti+1, disti+1, disti), 每个点与它的邻接点对比,取最小的,扫描每一行每一列,直到没有变更为止,代码如下:
class Solution
{
public:
vector<vector<int>> updateMatrix(vector<vector<int>> &matrix)
{vector<vector<int>> ret(matrix.size());
int max = 10001;
for (int i = 0; i < matrix.size(); i++)
{vector<int> vRow(matrix[i].size());
for (int j = 0; j < matrix[i].size(); j++)
{vRow[j] = matrix[i][j] == 0 ? 0 : max;
}
ret[i] = vRow;
}
bool b = true;
while (b)
{
b = false;
for (int i = 0; i < matrix.size(); i++)
{for (int j = 0; j < matrix[i].size(); j++)
{
//up
if (i - 1 >= 0 && ret[i][j] > ret[i - 1][j] + 1)
{
b = true;
ret[i][j] = ret[i - 1][j] + 1;
}
//down
if (i + 1 < matrix.size() && ret[i][j] > ret[i + 1][j] + 1)
{
b = true;
ret[i][j] = ret[i + 1][j] + 1;
}
//left
if (j - 1 >= 0 && ret[i][j] > ret[i][j - 1] + 1)
{
b = true;
ret[i][j] = ret[i][j - 1] + 1;
}
//right
if (j + 1 < matrix[i].size() && ret[i][j] > ret[i][j + 1] + 1)
{
b = true;
ret[i][j] = ret[i][j + 1] + 1;
}
}
}
}
return ret;
}
};
这种算法的时间复杂度为 O(r*c*k),其中 r 和 c 分别为行数和列数,k 是迭代的次数,如果 0 和 1 都相距很近的话,这个算法很快就迭代完成,然而如果 0 和 1 相距很远,比如矩阵只有左上角存在一个 0,那么右下角的 1 需要迭代约(r+c)/ 2 次,这样最糟的情况时间复杂度会上升一个级别,代码提交,耗时 188ms;
于是想另外一种算法减少冗余的计算,很容易就想到每个 0 点就像水里的波浪一样,一步一步的往四周扩散,每一次扩散(距离 +1),得到的结果就是最终结果,于是就联想到 BFS 算法,代码如下(耗时 168ms):
class Solution
{
public:
vector<vector<int>> updateMatrix(vector<vector<int>> &matrix)
{int row = matrix.size();
int col = matrix[0].size();
vector<vector<int>> ret(row, vector<int>(col, -1));
struct Point{
int x;
int y;
public:
Point(int _x, int _y) {
x = _x;
y = _y;
}
Point() {
x = 0;
y = 0;
}
};
struct Point p[10001];
int l = 0, r = 0;
for (int i = 0; i < row; i++)
{for (int j = 0; j < col; j++)
{if (matrix[i][j] == 0) {ret[i][j] = 0;
p[r++] = Point(i, j);
}
}
}
Point diff[4] = {{-1,0}, {1,0}, {0,-1}, {0,1}};
while (l < r) {Point cur = p[l++];
int nextDist = ret[cur.x][cur.y] + 1;
for (int i = 0; i < 4; i++) {int newX = cur.x + diff[i].x;
int newY = cur.y + diff[i].y;
if (newX >=0 && newX < row && newY >= 0 && newY < col && ret[newX][newY] == -1) {ret[newX][newY] = nextDist;
p[r++] = Point(newX, newY);
}
}
}
return ret;
}
};
这里有个点需要注意下,就是定义结构数组 struct Point p[10001],一开始我的 Point 结构只定义带参数的构造函数,然后这句 p[10001]的定义编译不过,网上查了下结构数组的定义,一大堆文章的解决方案都是定义数组的同时初始化数组,但我这里显然没办法初始化。后面想到既然没有初始化数据,那是否需要定义一个默认的无参数构造函数,果然加上之后编译通过了。
2.Review 阅读并点评至少一篇英文技术文章
这周阅读的文章是 GameDev Protips: How To Survive As An Indie Developer,作者 Daniel Doan 提出,作为一个游戏独立开发者,想要在游戏行业中生存下来,需要学会以下几点:
- 关注你熟悉的领域。如果你是逻辑性很强的,那就选择成为程序员,如果不擅长编码的,可以做美术,如果你熟悉财务和市场相关的知识,可以做游戏发行;
- 游戏尽量简洁。一开始堆大量粗糙的功能,先不考虑能否按时完成,就算完成质量也很糟,用户体验和市场效果都不好。正确的做法是从玩家角度出发,玩家操作要尽量简单,容易上手,这样玩家才能享受游戏的乐趣;
- 学会舍弃。当某些需求消耗你大量的时间、精力或者金钱,但它又不是核心的功能需求,那就有必要考虑舍弃它。因为我们的时间、技术、金钱等资源是有限的,需要把有限的资源花在重要的需求上,这是项目管理要做的事情;
- 善于寻求帮助 因为我们每个人都不是万能的,我们有自己擅长的领域,但是还有很多其他方面的知识我们是不懂的,这个时候就需要向外寻求帮助,把自己不擅长的部分外包出去。比如我不懂美术,可以请美术外包,我不懂推广,可以将游戏交给游戏发行公司进行推广。
3.Tip 学习至少一个技术技巧
最近开始用 vscode(以前习惯用 sublime),这里分享几个我觉得比较常用的快捷键和设置吧
- 在当前文件中快速定位接口的定义,Ctrl+Shift+O,然后输入关键字进行模糊搜索
- 通过文件名快速在当前文件目录下查找该文件,Ctrl+P,然后输入文件名关键字进行模糊匹配
- 跳转到接口的定义后,可以通过 Alt+←返回,类似的,通过 Alt+→往前跳转
- 格式化代码,选中需要格式化的代码块后,Ctrl+K+ F 就可以
- 修改代码 Tab 的缩进长度,File->Preferences->Settings,修改 Commonly Used 里面的 Editor:Tab Size. 然而有些时候修改了却没有生效,那是因为 Editor:Detect Indentation 被勾上了,它选中的意思是如果检测到原来代码的 Tab 缩进是 2,就算设置了 4,vscode 会临时改为 2,需要把这个选项去掉
4.Share 分享一篇有观点和思考的技术文章
分享一篇关于服务调用的文章
终于有人把服务调用说清楚了