文章目录
- 1. 题目来源
- 2. 题目解析
1. 题目来源
链接:2711. 对角线上不同值的数量差
前置题:
- [M模拟] lc3446. 按对角线进行矩阵排序(对角线遍历+公式推导+模板题)
- 矩形的对角线遍历的基础题。
题单:
- 待补充
2. 题目解析
2025年03月25日21:21:28
方法一:暴力
- 由于这个题目数据量太小了哈,就完全可以暴力来做,每次去暴力判断下左上侧、右下侧对角线的重复元素个数即可。
方法二:前后缀分解
- 暴力显然在同一个对角线上有很多元素被重复遍历。
- 这个时候就需要对角线的前后缀分解。确保重复遍历次数较少。
- 直接遍历每一条对角线元素。
- 从左上方到右下方这样的遍历方向。
- 同时统计左上方对角线的不同元素个数。作为前缀统计,直接放到答案中。
- 再从右下方到左上方这样的遍历方向。
- 此时就可以直接计算答案了,同时统计 右下方 到 左上方 对角线的不同元素个数。作为后缀统计,直接与前缀元素计算答案即可。
- 所以,每个元素至多被遍历两遍。
方法三:状态压缩+前后缀分解
- 这个没啥难度哈,一个简单的状态压缩,将 set 使用一个 uint64 的数字进行代替,是完全可以的哈。
- 注意里面一些位运算的 API 和技巧 即可。
- 时间复杂度: O ( n m ) O(nm) O(nm)
- 空间复杂度: O ( 1 ) O(1) O(1) 返回值不计算
方法二:前后缀分解
func differenceOfDistinctValues(grid [][]int) [][]int {n, m := len(grid), len(grid[0])res := make([][]int, n)for i := range n {res[i] = make([]int, m)}set := map[int]struct{}{}for k := 1; k < n + m; k ++ {minJ, maxJ := max(0, m - k), min(m - 1, n - 1 - k + m)clear(set) for j := minJ; j <= maxJ; j ++ { // 处理前缀i := j + k - mres[i][j] = len(set) // 不包含(i, j) 注意顺序set[grid[i][j]] = struct{}{} }clear(set)for j := maxJ; j >= minJ; j -- { // 处理后缀,计算答案i := j + k - mres[i][j] = abs(res[i][j] - len(set))set[grid[i][j]] = struct{}{}}}return res
}func abs(x int) int { if x < 0 { return -x } return x
}
方法一:暴力
func differenceOfDistinctValues(grid [][]int) [][]int {n, m := len(grid), len(grid[0])res := make([][]int, n)for i := range n {res[i] = make([]int, m)}getL := func(x, y int) int {s := map[int]struct{}{}x -- y -- for x >= 0 && y >= 0 {s[grid[x][y]] = struct{}{}x --y --}return len(s)}getR := func(x, y int) int {s := map[int]struct{}{}x ++ y ++ for x < n && y < m {s[grid[x][y]] = struct{}{}x ++y ++}return len(s)}abs := func(x int) int {if x > 0 {return x}return -x}for i := range n {for j := range m {res[i][j] = abs(getL(i, j) - getR(i, j))}}return res
}