一 目录
不折腾的前端,和咸鱼有什么区别
目录 |
---|
一 目录 |
二 前言 |
三 解题及测试 |
四 LeetCode Submit |
五 解题思路 |
六 进一步思考 |
二 前言
难度:简单
涉及知识:深度优先搜索
题目地址:https://leetcode-cn.com/problems/flood-fill/
题目内容:
有一幅以二维整数数组表示的图画,
每一个整数表示该图画的像素值大小,
数值在 0 到 65535 之间。
给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列),
和一个新的颜色值 newColor,让你重新上色这幅图像。
为了完成上色工作,
从初始坐标开始,
记录初始坐标的上下左右四个方向上像素值,
与初始坐标相同的相连像素点,
接着再记录这四个方向上符合条件的像素点,
与他们对应四个方向上像素值与初始坐标相同的相连像素点,
……,
重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。
最后返回经过上色渲染后的图像。
示例 1:
输入:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析:
在图像的正中间,(坐标(sr,sc)=(1,1)),
在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,
因为它不是在上下左右四个方向上与初始点相连的像素点。
注意:
image 和 image[0] 的长度在范围 [1, 50] 内。
给出的初始点将满足:
0 <= sr < image.length 和 0 <= sc < image[0].length。
image[i][j] 和 newColor 表示的颜色值在范围 [0, 65535]内。
三 解题及测试
小伙伴可以先自己在本地尝试解题,再回来看看 jsliang 的解题思路。
LeetCode 给定函数体:
/**
* @param {number[][]} image
* @param {number} sr
* @param {number} sc
* @param {number} newColor
* @return {number[][]}
*/
var floodFill = function(image, sr, sc, newColor) {
};
根据上面的已知函数,尝试破解本题吧~
确定了自己的答案再看下面代码哈~
index.js
/**
* @name 图像渲染
* @param {number[][]} image
* @param {number} sr
* @param {number} sc
* @param {number} newColor
* @return {number[][]}
*/
const floodFill = (image, sr, sc, newColor) => {
const oldColor = image[sr][sc]; // 旧颜色
const drawList = [[sr, sc]]; // 剩余可描点
const mapRoute = new Map(); // 哈希表 - 记录走过的路径
while (drawList.length) {
const tempP = drawList.pop(); // 当前可描点 - tempPosition
const p1 = tempP[0]; // 当前可描点 - 横坐标 - position1
const p2 = tempP[1]; // 当前可描点 - 纵坐标 - position2
if (mapRoute.get(`${p1}${p2}`) === undefined) { // 走过的路不要重复
image[p1][p2] = newColor;
if (p1 - 1 >= 0 && image[p1 - 1][p2] === oldColor) {
drawList.push([p1 - 1, p2]);
}
if (p2 - 1 >= 0 && image[p1][p2 - 1] === oldColor) {
drawList.push([p1, p2 - 1]);
}
if (p1 + 1 < image.length && image[p1 + 1][p2] === oldColor) {
drawList.push([p1 + 1, p2]);
}
if (p2 + 1 < image[0].length && image[p1][p2 + 1] === oldColor) {
drawList.push([p1, p2 + 1]);
}
}
mapRoute.set(`${p1}${p2}`, true);
}
return image;
};
console.log(
floodFill(
[
[1, 1, 1],
[1, 1, 0],
[1, 0, 1]
],
1,
1,
2,
)
);
node index.js
返回:
[
[ 2, 2, 2 ],
[ 2, 2, 0 ],
[ 2, 0, 1 ],
]
四 LeetCode Submit
Accepted
* 277/277 cases passed (80 ms)
* Your runtime beats 96.92 % of javascript submissions
* Your memory usage beats 60 % of javascript submissions (36.6 MB)
五 解题思路
孩子没娘,说来话长。
咋看这道题还是挺绕的,不过不要太 care 啦,jsliang 为你一一道来:
jsliang 破解
const floodFill = (image, sr, sc, newColor) => {
const oldColor = image[sr][sc]; // 旧颜色
const drawList = [[sr, sc]]; // 剩余可描点
const mapRoute = new Map(); // 哈希表 - 记录走过的路径
while (drawList.length) {
const tempP = drawList.pop(); // 当前可描点 - tempPosition
const p1 = tempP[0]; // 当前可描点 - 横坐标 - position1
const p2 = tempP[1]; // 当前可描点 - 纵坐标 - position2
if (mapRoute.get(`${p1}${p2}`) === undefined) { // 走过的路不要重复
image[p1][p2] = newColor;
if (p1 - 1 >= 0 && image[p1 - 1][p2] === oldColor) {
drawList.push([p1 - 1, p2]);
}
if (p2 - 1 >= 0 && image[p1][p2 - 1] === oldColor) {
drawList.push([p1, p2 - 1]);
}
if (p1 + 1 < image.length && image[p1 + 1][p2] === oldColor) {
drawList.push([p1 + 1, p2]);
}
if (p2 + 1 < image[0].length && image[p1][p2 + 1] === oldColor) {
drawList.push([p1, p2 + 1]);
}
}
mapRoute.set(`${p1}${p2}`, true);
}
return image;
};
首先,我们先明确一些变量:
oldColor
:题目表明所有相邻的旧颜色都要换成新颜色,所以我们肯定要知道旧颜色是多少的。drawList
:关键列表,我们将当前可描的点,都加入到drawList
中,将它所有可描的点都遍历一遍,我们就走完了所有点。mapRoute
:走过的点,[1, 1]
的上边是[0, 1]
,[0, 1]
的下边是[1, 1]
……如果我们不做限制,它们可以不断重复,这就会造成死循环啦!所以我们用mapRoute
记录走过的点。
OK,定义完毕,开始遍历 drawList
,在遍历之前,先介绍它内部的一些变量:
tempP
:我们通过tempPosition
来表明当前需要走的点。p1
:我们tempP
的横坐标。p2
:我们tempP
的纵坐标。
然后,我们开始描点:
如果这个点曾经出现在
mapRoute
,那么我们就不遍历它了!如果这个点没有出现在
mapRoute
,那么设置image[p1][p2] = newColor
,即这个点被我们占领了,打上了newColor
的标志。判断上下左右四个坐标,以及坐标的值是不是和
oldColor
相同,如果相同,则添加到drawList
可描列表上去。
最后,通过 drawList
的不断判断,我们将所有可描的点都走了一遍。
Submit 提交:
Accepted
* 277/277 cases passed (80 ms)
* Your runtime beats 96.92 % of javascript submissions
* Your memory usage beats 60 % of javascript submissions (36.6 MB)
六 进一步思考
在这道题中,我们使用了迭代的方式,那么小伙伴能不能使用递归来进行解决呢?
如果你有更好的思路想法,欢迎评论留言或者私聊 jsliang~
不折腾的前端,和咸鱼有什么区别!
jsliang 会每天更新一道 LeetCode 题解,从而帮助小伙伴们夯实原生 JS 基础,了解与学习算法与数据结构。
浪子神剑 会每天更新面试题,以面试题为驱动来带动大家学习,坚持每天学习与思考,每天进步一点!
扫描上方二维码,关注 jsliang 的公众号(左)和 浪子神剑 的公众号(右),让我们一起折腾!
jsliang 的文档库 由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于https://github.com/LiangJunrong/document-library上的作品创作。
本许可协议授权之外的使用权限可以从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处获得。