2025-11-16:子矩阵的最小绝对差。用go语言,给定一个大小为 m×n 的整数矩阵 grid 和一个整数 k。 对于矩阵中每一个连续的 k×k 区域,求该

38 阅读5分钟

2025-11-16:子矩阵的最小绝对差。用go语言,给定一个大小为 m×n 的整数矩阵 grid 和一个整数 k。

对于矩阵中每一个连续的 k×k 区域,求该区域内任意两个不同元素之间数值差的最小绝对值。把对每个左上角位于 (i, j) 的 k×k 子块得到的结果按位置放入一个尺寸为 (m - k + 1) × (n - k + 1) 的二维数组 ans,其中 ans[i][j] 就是以 (i, j) 为左上角的子块的答案。若某个子块内所有元素都相同,则它的结果记为 0。

注:这里的子矩阵(子块)是指所有满足 x1 ≤ x ≤ x2 且 y1 ≤ y ≤ y2 的单元格所组成的矩形区域。

1 <= m == grid.length <= 30。

1 <= n == grid[i].length <= 30。

-100000 <= grid[i][j] <= 100000。

1 <= k <= min(m, n)。

输入: grid = [[1,8],[3,-2]], k = 2。

输出: [[2]]。

解释:

只有一个可能的 k x k 子矩阵:[[1, 8], [3, -2]]。

子矩阵中的不同值为 [1, 8, 3, -2]。

子矩阵中的最小绝对差为 |1 - 3| = 2。因此,答案为 [[2]]。

题目来自力扣3567。

分步骤过程描述

  1. 初始化阶段

    • 获取输入矩阵 grid 的维度 m(行数)和 n(列数)。
    • 创建结果矩阵 ans,其尺寸为 (m - k + 1) × (n - k + 1),用于存储每个 k × k 子矩阵的最小绝对差。初始化时,ans 的所有元素默认值为 0(符合题目要求:若子矩阵元素全相同,结果记为 0)。
    • 预分配一个长度为 的临时数组 arr,用于高效存储每个子矩阵的元素,避免重复内存分配。
  2. 遍历所有可能的子矩阵

    • 外层循环遍历行起始索引 i(范围:0m - k),内层循环遍历列起始索引 j(范围:0n - k)。每个 (i, j) 对应一个以 (i, j) 为左上角的 k × k 子矩阵。
    • 对于每个子矩阵:
      • 提取元素:通过嵌套循环遍历该子矩阵的所有行(ii + k - 1)和所有列(jj + k - 1),将元素依次存入临时数组 arr 的切片 a 中(通过 arr[:0] 重用内存,减少开销)。
      • 排序元素:对切片 a 中的 个元素进行升序排序(使用 Go 的 slices.Sort)。排序后,最小绝对差必然出现在相邻元素之间。
      • 计算最小绝对差
        • 初始化 res 为一个极大值(math.MaxInt)。
        • 遍历排序后的 a,计算每对相邻元素的差(a[p] - a[p-1]),并更新 res 为这些差的最小值。
        • 如果 res 未被更新(即子矩阵元素全相同或仅有一个元素),则结果保持 0;否则将 res 赋值给 ans[i][j]
  3. 返回结果

    • 遍历完成后,返回结果矩阵 ans,其中每个位置 ans[i][j] 存储了对应子矩阵的最小绝对差。

时间复杂度分析

  • 子矩阵总数:存在 (m - k + 1) × (n - k + 1) 个子矩阵,其数量级为 O(mn)
  • 单个子矩阵的处理:
    • 元素提取:需要复制 个元素,时间复杂度为 O(k²)
    • 排序:对 个元素排序,基于比较的排序算法(如 Go 的 slices.Sort)时间复杂度为 O(k² log k²) = O(k² log k)
    • 计算相邻差:遍历排序后的数组,时间复杂度为 O(k²)
  • 总时间复杂度:子矩阵数量 × 单个子矩阵处理时间,即 O(mn × k² log k)
    (注:由于 k ≤ min(m, n)m, n ≤ 30,该算法在给定约束下可行。)

空间复杂度分析

  • 额外空间(不包括输入和输出):
    • 临时数组 arr:固定大小为 ,用于存储子矩阵元素,空间复杂度为 O(k²)
    • 排序操作:递归排序算法(如快速排序)的栈空间复杂度为 O(log k²) = O(log k)
  • 总额外空间复杂度:O(k²)(主导项)。
    (注:结果矩阵 ans 是输出必要空间,通常不计入额外空间复杂度。)

关键点说明

  • 优化策略:通过重用临时数组 arr 避免重复内存分配,减少开销。
  • 算法依据:利用排序后最小差必出现在相邻元素间的性质,确保正确性。
  • 约束处理:当 k = 1 时,子矩阵仅有一个元素,结果直接为 0;当 k > 1 时,正常计算相邻差。

此方法直接但有效,适用于题目中的小规模约束(m, n ≤ 30)。

Go完整代码如下:

package main

import (
	"fmt"
	"math"
	"slices"
)

func minAbsDiff(grid [][]int, k int) [][]int {
	m, n := len(grid), len(grid[0])
	ans := make([][]int, m-k+1)
	arr := make([]int, k*k)
	for i := range ans {
		ans[i] = make([]int, n-k+1)
		for j := range ans[i] {
			a := arr[:0] // 避免反复 make
			for _, row := range grid[i : i+k] {
				a = append(a, row[j:j+k]...)
			}
			slices.Sort(a)

			res := math.MaxInt
			for p := 1; p < len(a); p++ {
				if a[p] > a[p-1] {
					res = min(res, a[p]-a[p-1])
				}
			}
			if res < math.MaxInt {
				ans[i][j] = res
			}
		}
	}
	return ans
}

func main() {
	grid := [][]int{{1, 8}, {3, -2}}
	k := 2
	result := minAbsDiff(grid, k)
	fmt.Println(result)
}

在这里插入图片描述

Python完整代码如下:

# -*-coding:utf-8-*-

import math

def minAbsDiff(grid, k):
    m, n = len(grid), len(grid[0])
    ans = [[0] * (n - k + 1) for _ in range(m - k + 1)]
    
    for i in range(len(ans)):
        for j in range(len(ans[0])):
            # 提取k×k子矩阵并展平
            a = []
            for row in grid[i:i+k]:
                a.extend(row[j:j+k])
            a.sort()
            
            # 计算相邻非重复元素的最小差值
            res = math.inf
            for p in range(1, len(a)):
                if a[p] > a[p-1]:
                    res = min(res, a[p] - a[p-1])
            
            if res < math.inf:
                ans[i][j] = res
    
    return ans

def main():
    grid = [[1, 8], [3, -2]]
    k = 2
    result = minAbsDiff(grid, k)
    print(result)

if __name__ == "__main__":
    main()

在这里插入图片描述

C++完整代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
#include <cmath>

using namespace std;

vector<vector<int>> minAbsDiff(vector<vector<int>>& grid, int k) {
    int m = grid.size();
    int n = grid[0].size();
    vector<vector<int>> ans(m - k + 1, vector<int>(n - k + 1, 0));

    for (int i = 0; i <= m - k; i++) {
        for (int j = 0; j <= n - k; j++) {
            vector<int> arr;
            arr.reserve(k * k); // 预分配空间提高效率

            // 提取k×k子矩阵
            for (int x = i; x < i + k; x++) {
                for (int y = j; y < j + k; y++) {
                    arr.push_back(grid[x][y]);
                }
            }

            // 排序
            sort(arr.begin(), arr.end());

            // 计算相邻非重复元素的最小差值
            int res = INT_MAX;
            for (int p = 1; p < arr.size(); p++) {
                if (arr[p] > arr[p-1]) {
                    res = min(res, arr[p] - arr[p-1]);
                }
            }

            if (res < INT_MAX) {
                ans[i][j] = res;
            }
        }
    }

    return ans;
}

int main() {
    vector<vector<int>> grid = {{1, 8}, {3, -2}};
    int k = 2;
    vector<vector<int>> result = minAbsDiff(grid, k);

    // 输出结果
    cout << "[";
    for (int i = 0; i < result.size(); i++) {
        cout << "[";
        for (int j = 0; j < result[i].size(); j++) {
            cout << result[i][j];
            if (j < result[i].size() - 1) {
                cout << ",";
            }
        }
        cout << "]";
        if (i < result.size() - 1) {
            cout << ",";
        }
    }
    cout << "]" << endl;
    return 0;
}

在这里插入图片描述