LeetCode - 832. Flipping an Image
1. 问题背景
今天我们要探讨的是 LeetCode 第 832 题 Flipping an Image。这是一道关于二维数组变换的基础算法题,主要考察我们对数组操作和双指针技巧的运用。
题目描述
给定一个二进制矩阵image,先水平翻转图像,然后反转图像。返回最终结果。
- 水平翻转图像:将图像的每一行进行翻转,即行的第一个元素与最后一个元素交换,第二个元素与倒数第二个元素交换,依此类推。
- 反转图像:将每个元素进行取反,0 变为 1,1 变为 0。
示例
输入:[[1,1,0],[1,0,1],[0,0,0]]
输出:[[1,0,0],[0,1,0],[1,1,1]]
解释:
- 水平翻转每一行:
[[0,1,1],[1,0,1],[0,0,0]]- 反转每一个元素:
[[1,0,0],[0,1,0],[1,1,1]]
2. 解题思路分析
这个问题的核心在于如何高效地完成两个操作:行翻转和元素取反。我们可以通过以下步骤来解决:
- 遍历每一行:对矩阵中的每一行进行处理。
- 双指针法翻转并取反:
- 使用两个指针
j和k分别指向行的首尾两端 - 在指针相向移动的过程中,交换元素并取反
- 当
j == k时(处理奇数长度的行),只需对该元素取反一次
- 使用两个指针
这种方法的时间复杂度是 O(n²),其中 n 是矩阵的边长,因为我们需要遍历矩阵中的每个元素一次。空间复杂度是 O(1),因为我们是在原矩阵上进行修改,不需要额外的存储空间。
3. JavaScript 解法实现
/**
* @param {number[][]} image
* @return {number[][]}
*/
var flipAndInvertImage = function(image) {
for (let i = 0; i < image.length; i++) {
let row = image[i];
for (let j = 0, k = row.length - 1; j <= k; j++, k--) {
// 交换元素
let temp = row[j];
row[j] = row[k];
row[k] = temp;
// 取反操作 - 交换后 j 和 k 位置的元素都需要取反
row[j] = row[j] === 0 ? 1 : 0;
if (j !== k) {
row[k] = row[k] === 0 ? 1 : 0;
}
}
}
return image;
};
4. Python 解法实现
class Solution:
def flipAndInvertImage(self, image: List[List[int]]) -> List[List[int]]:
for i in range(len(image)):
row = image[i]
j, k = 0, len(row) - 1
while j <= k:
# 交换元素
row[j], row[k] = row[k], row[j]
# 取反操作
row[j] = 1 - row[j]
if j != k:
row[k] = 1 - row[k]
j += 1
k -= 1
return image
5. 解法优化与变种思考
上述解法已经是最优解,但我们可以通过位运算来进一步简化取反操作:
- 在 JavaScript 中,可以使用
1 - x或x ^ 1替代条件判断 - 在 Python 中,可以使用
1 - x替代条件判断
变种问题思考:
- 如果矩阵不是二进制矩阵(元素可能是 0, 1, 2),如何修改代码?
- 如果要求先取反再翻转,应该如何调整算法?
- 如果矩阵非常大,如何进行并行处理以提高效率?
6. 总结
这道题展示了双指针技巧在数组操作中的应用,通过一次遍历同时完成翻转和取反操作,实现了时间和空间的最优解。在解决类似的数组变换问题时,我们应该优先考虑原地操作以减少空间复杂度,同时利用双指针法提高遍历效率。
希望这篇解析能帮助你更好地理解如何处理二维数组变换问题。如果你有任何疑问或其他解法,欢迎在评论区留言讨论!
1006

被折叠的 条评论
为什么被折叠?



