leetcode:311. 稀疏矩阵的乘法(会员题)
lintcode:654 · 稀疏矩阵乘法

题目

给定两个 稀疏矩阵 A 和 B,返回 AB 的结果。
您可以假设 A 的列数等于 B 的行数。

示例:

  1. 输入:
  2. [[1,0,0],[-1,0,3]]
  3. [[7,0,0],[0,0,0],[0,0,1]]
  4. 输出:
  5. [[7,0,0],[-7,0,3]]
  6. 解释:
  7. A = [
  8. [ 1, 0, 0],
  9. [-1, 0, 3]
  10. ]
  11. B = [
  12. [ 7, 0, 0 ],
  13. [ 0, 0, 0 ],
  14. [ 0, 0, 1 ]
  15. ]
  16. | 1 0 0 | | 7 0 0 | | 7 0 0 |
  17. AB = | -1 0 3 | x | 0 0 0 | = | -7 0 3 |
  18. | 0 0 1 |
  1. 输入:
  2. [[1,0],[0,1]]
  3. [[0,1],[1,0]]
  4. 输出:
  5. [[0,1],[1,0]]

解答 & 代码

解法一:模拟(暴力,三重循环)

[中等] 311. 稀疏矩阵的乘法 - 图1

  1. class Solution {
  2. public:
  3. /**
  4. * @param a: a sparse matrix
  5. * @param b: a sparse matrix
  6. * @return: the result of A * B
  7. */
  8. vector<vector<int>> multiply(vector<vector<int>> &a, vector<vector<int>> &b) {
  9. int rows = a.size(); // 结果矩阵的行数(a 矩阵的行数)
  10. int cols = b[0].size(); // 结果矩阵的列数(b 矩阵的列数)
  11. int dim = a[0].size(); // 中间维度(a 矩阵的列数、b 矩阵的行数)
  12. vector<vector<int>> result(rows, vector<int>(cols, 0)); // 结果矩阵
  13. // 三重循环
  14. for(int i = 0; i < rows; ++i)
  15. {
  16. for(int j = 0; j < cols; ++j)
  17. {
  18. // 计算 result[i][j],等于 a 矩阵第 i 行和 b 矩阵第 j 列对应元素相乘再求和
  19. for(int k = 0; k < dim; ++k)
  20. result[i][j] += a[i][k] * b[k][j];
  21. }
  22. }
  23. return result;
  24. }
  25. };

复杂度分析:设 a 矩阵 rows 行 dim 列,b 矩阵 dim 行 cols 列

  • 时间复杂度 O(rows cols dim):
  • 空间复杂度 O(1):结果矩阵的空间复杂度不计入

执行结果:

  1. 执行结果:通过
  2. 执行用时:61 ms, 在所有 C++ 提交中击败了 57.80% 的用户
  3. 内存消耗:5.41 MB, 在所有 C++ 提交中击败了 57.80% 的用户

解法二:哈希表存储稀疏矩阵

  1. class Solution {
  2. private:
  3. // 用哈希表存储稀疏矩阵matrix的非零元素,key = 行号,val = 哈希表(key=列号,val=非零元素值)
  4. unordered_map<int, unordered_map<int, int>> saveSparseMatrix(vector<vector<int>> &matrix, int rows, int cols)
  5. {
  6. unordered_map<int, unordered_map<int, int>> hashMap;
  7. for(int i = 0; i < rows; ++i)
  8. {
  9. unordered_map<int, int> rowMap;
  10. for(int j = 0; j < cols; ++j)
  11. {
  12. if(matrix[i][j] != 0) // 哈希表中只存储非零元素
  13. rowMap[j] = matrix[i][j];
  14. }
  15. hashMap[i] = rowMap;
  16. }
  17. return hashMap;
  18. }
  19. public:
  20. /**
  21. * @param a: a sparse matrix
  22. * @param b: a sparse matrix
  23. * @return: the result of A * B
  24. */
  25. vector<vector<int>> multiply(vector<vector<int>> &a, vector<vector<int>> &b) {
  26. int M = a.size(); // 结果矩阵的行数(a 矩阵的行数)
  27. int K = a[0].size(); // 结果矩阵的列数(b 矩阵的列数)
  28. int N = b[0].size(); // 中间维度(a 矩阵的列数、b 矩阵的行数)
  29. vector<vector<int>> result(M, vector<int>(N, 0)); // 结果矩阵
  30. // 分别用哈希表存储矩阵 a、矩阵 b 的非零元素
  31. unordered_map<int, unordered_map<int, int>> aMap = saveSparseMatrix(a, M, K);
  32. unordered_map<int, unordered_map<int, int>> bMap = saveSparseMatrix(b, K, N);
  33. for(int i = 0; i < M; ++i)
  34. {
  35. unordered_map<int, int> aiMap = aMap[i];
  36. // 遍历矩阵 a 的每个非零元素 aik(第 i 行第 k 列个元素)
  37. for(auto itA = aiMap.begin(); itA != aiMap.end(); ++itA)
  38. {
  39. int k = itA->first;
  40. int aik = itA->second;
  41. unordered_map<int, int> bkMap = bMap[k];
  42. // 遍历矩阵 b 的第 k 行非零元素 bkj
  43. // 因为矩阵 a 的第 k 列元素会和矩阵 b 第 k 行的每个元素相乘,加到 result[i][j]
  44. for(auto itB = bkMap.begin(); itB != bkMap.end(); ++itB)
  45. {
  46. int j = itB->first;
  47. int bkj = itB->second;
  48. result[i][j] += aik * bkj;
  49. }
  50. }
  51. }
  52. return result;
  53. }
  54. };

执行结果:

  1. 执行结果:通过
  2. 执行用时:41 ms, 在所有 C++ 提交中击败了 98.40% 的用户
  3. 内存消耗:4.58 MB, 在所有 C++ 提交中击败了 98.40% 的用户