2503. 矩阵查询可获得的最大分数

241 阅读3分钟

题目:
给你一个大小为 m x n 的整数矩阵 grid 和一个大小为 k 的数组 queries 。

找出一个大小为 k 的数组 answer ,且满足对于每个整数 queres[i] ,你从矩阵 左上角 单元格开始,重复以下过程:

  • 如果 queries[i] 严格 大于你当前所处位置单元格,如果该单元格是第一次访问,则获得 1 分,并且你可以移动到所有 4 个方向(上、下、左、右)上任一 相邻 单元格。
  • 否则,你不能获得任何分,并且结束这一过程。

在过程结束后,answer[i] 是你可以获得的最大分数。注意,对于每个查询,你可以访问同一个单元格 多次 。

返回结果数组 answer 。
算法:
方法一:并查集
说明一下运行过程,以默认输入: grid = [[1,2,3],[2,5,7],[3,5,1]], queries = [5,6,2]为例
排序后的queries->queriesArr[2,5,6]和grid排序后的arr=[1,1,2,2,3,3,5,5,7],queriesArr和arr双指针。

  • step 1,第一次查询,query=2,arr=[0,1]所以下图中grid编号为0和8的节点,通过并查集自己联通自己:
    image.png
    和grid[0][0]联通的节点数为1个
  • step 2,第二次查询从query=5,arr遍历了值[2,2,3,3],grid编号1,2,3,6的节点和step 1中联通的节点联通:

image.png
和grid[0][0]联通的节点数为5个

  • step 2,第二次查询从query=6,arr遍历了值[5,5],grid编号4,7的节点和step 2中联通的节点联通:

image.png
和grid[0][0]联通的节点数为8个。

注意:
1.对grid一维化,在step 1将 grid[0][0]和grid[2][2],通过并查集分别连接到自己,对结果没有影响的,等于grid[2][2]形成了一个孤岛。如果这个孤岛可以和grid[0][0]联通,那就说明能访问到这个孤岛,合并size和uniondfind
2.在遍历完所有的grid节点之后,不同节点的father可能不是同一个,而是存在孙->父->爷的关系(标记的节点是联通的,从子节点到爷爷结点之间存在父亲节点):

image.png
3.双指针+排序,充分利用了上一次的计算结果

var unionfind []int
var size []int
func maxPoints(grid [][]int, queries []int) []int {
    ans := make([]int, len(queries))
    row, col := len(grid), len(grid[0])
    mn := row * col
    // 初始化并查集和连通块size
    unionfind = make([]int, mn)
    size = make([]int, mn)
    for i := range unionfind {
        unionfind[i] = i
        size[i] = 1
    }
    
    dicts := [][]int{[]int{-1,0},[]int{1,0},[]int{0,-1},[]int{0,1}}
    // 对grid展开,排序
    arr := make([][]int, 0)
    for i := range grid {
        for j, val := range grid[i] {
            arr = append(arr, []int{i, j, val })
        }
    }
    sort.Slice(arr, func(i, j int) bool {return arr[i][2] < arr[j][2]})

    // 对queries排序
    queriesArr := make([]int, len(queries))
    for i := range queriesArr {
        queriesArr[i] = i
    }
    sort.Slice(queriesArr, func(i, j int) bool {return queries[queriesArr[i]] < queries[queriesArr[j]]})
	j := 0
    for _, i := range queriesArr {
        queryVal := queries[i] 
        for ;j < len(arr) && arr[j][2] < queryVal; j ++ {
            x, y := arr[j][0], arr[j][1]
            for _, dict := range dicts {
                x2, y2 := x + dict[0], y + dict[1]
                if 0 <= x2 && x2 < row && 0 <= y2 && y2 < col && grid[x2][y2] < queryVal {
                    merge(x * col + y, x2 * col + y2)
                }
            }
        } 
        if grid[0][0] < queryVal {
            ans[i] = size[find(0)]
        }
        // fmt.Println(queryVal, unionfind, size)
        
    }
    return ans
}

func find(x int) int {
    if unionfind[x] == x {
        return x
    }
    unionfind[x] = find(unionfind[x])
    return unionfind[x]
}

func merge(from int, to int) {
    fromFather := find(from)
    toFather := find(to)
    if fromFather != toFather {
        // fmt.Println("merge", from, to, fromFather,toFather)
        unionfind[fromFather] = toFather
        size[toFather] = size[toFather] + size[fromFather]
    }
}

方法二:最小堆
方法一对grid一维化,为了得到grid的有序数组,想到有序,这里也可以用最小堆

var  dicts = [][]int{[]int{-1,0},[]int{1,0},[]int{0,-1},[]int{0,1}}
func maxPoints(grid [][]int, queries []int) []int {
    ans := make([]int, len(queries))
    row, col := len(grid), len(grid[0])  
   
    // 对queries排序
    queriesArr := make([]int, len(queries))
    for i := range queriesArr {
        queriesArr[i] = i
    }
    sort.Slice(queriesArr, func(i, j int) bool {return queries[queriesArr[i]] < queries[queriesArr[j]]})
	h := hp{{grid[0][0], 0, 0}}
    grid[0][0] = 0
    count := 0
    for _, i := range queriesArr {
        queryVal := queries[i] 
        // fmt.Println(queryVal)
        for len(h) > 0 && h[0].val < queryVal  {
            count ++
            p := heap.Pop(&h).(tuple)
            // fmt.Println(queryVal,":", p)
            for _, dict := range dicts {
                x2, y2 := p.i + dict[0], p.j + dict[1]
                if 0 <= x2 && x2 < row && 0 <= y2 && y2 < col && grid[x2][y2] > 0 {
                   // 注意这个顺序不能变。
                   heap.Push(&h, tuple{grid[x2][y2], x2, y2})
                   grid[x2][y2] = 0
                }
            }
        } 
        ans[i] = count      
    }
    return ans
}

type tuple struct{ val, i, j int }
type hp []tuple
func (h hp) Len() int            { return len(h) }
func (h hp) Less(i, j int) bool  { return h[i].val < h[j].val }
func (h hp) Swap(i, j int)       { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v interface{}) { *h = append(*h, v.(tuple)) }
func (h *hp) Pop() interface{}   { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }