【菜鸡刷题 - leetcode1631 最小体力消耗路径】解法一: 队列优化迪杰斯特拉 & python自带堆排序 || 解法二: 并查集 | python


@author=YHR | 转载请标明来源


文章目录

  • 题目描述
  • 题目解读
  • 思路一: 队列优化迪杰斯特拉
    • 传统迪杰斯特拉
    • 队列优化的迪杰斯特拉
    • python 自带的堆排序 与 list.sort()
    • 本题解读 & 代码
  • 思路二:并查集
    • 上代码先


题目描述

题目解读

思路一: 队列优化迪杰斯特拉

传统迪杰斯特拉

队列优化的迪杰斯特拉

python 自带的堆排序 与 list.sort()

本题解读 & 代码

class Solution:
    def __init__(self):
        self.inf = int(1e6 + 1)

    def minimumEffortPath(self, heights):
        self.rows = len(heights)
        if self.rows > 0:
            self.cols = len(heights[0])
            if self.cols > 0:
                aim = self.rows * self.cols - 1
                start = 0
                Dist = self.Dijstra(heights, start)
                return Dist[aim]

        return 0

    def getRowAndColByIndex(self, index):
        row = index // self.cols
        col = index % self.cols

        return row, col


    def Dijstra(self, heights, start):
        totalNodesNum = self.rows * self.cols

        dir = [[0, -1], [0, 1], [-1, 0], [1, 0]]
        hasSeen = [0] * totalNodesNum  # 0表示未遍历,1表示已经纳入了遍历

        # intial the distance from start to others
        Dist = [self.inf] * totalNodesNum;
        Dist[start] = 0
        import heapq
        # initial the sorted queue
        candidate = []
        heapq.heapify(candidate)    
        heapq.heappush(candidate, [Dist[start], start])

        while len(candidate) > 0:
            [Dist2nownode, nownode] = heapq.heappop(candidate)

            if hasSeen[nownode] == 1:
                continue
            else:
                hasSeen[nownode] = 1

            now_r, now_c = self.getRowAndColByIndex(nownode)
            for _ in range(4):
                new_r = now_r + dir[_][0]
                new_c = now_c + dir[_][1]

                if 0 <= new_r < self.rows and 0 <= new_c < self.cols:
                    if hasSeen[new_r * self.cols + new_c] != 1:
                        if Dist[new_r * self.cols + new_c] > max(Dist2nownode,
                                                                 abs(heights[now_r][now_c] - heights[new_r][new_c])):
                            Dist[new_r * self.cols + new_c] = max(Dist2nownode,
                                                                  abs(heights[now_r][now_c] - heights[new_r][new_c]))
                            heapq.heappush(candidate, [Dist[new_r * self.cols + new_c], new_r * self.cols + new_c])

        return Dist

思路二:并查集

上代码先

import heapq
class Solution:
    def __init__(self):
        self.inf = int(1e6 + 1)

    def minimumEffortPath(self, heights):
        self.rows = len(heights)
        if self.rows > 0:
            self.cols = len(heights[0])
            if self.cols > 0:
                self.totalNodeNums = self.rows * self.cols
                return self.unionAndSearchWithKruskal(heights, self.totalNodeNums-1)
        return 0

    def getRowAndColByIndex(self, index):
        row = index // self.cols
        col = index % self.cols

        return row, col
    

    def getEdges(self, heights):
        edges = []
        heapq.heapify(edges)  # sort by element 0, small heap
        # kruskal 获取边
        for _ in range(self.totalNodeNums):
            this_r, this_c = self.getRowAndColByIndex(_)
            # 获取到右边 边
            if this_c < self.cols-1:
                next_r , next_c = this_r, this_c+1
                heapq.heappush(edges, [abs(heights[next_r][next_c] - heights[this_r][this_c]), _, next_r*self.cols + next_c])


            # 获取到下面 边 
            if this_r < self.rows-1:
                next_r , next_c = this_r+1, this_c
                heapq.heappush(edges, [abs(heights[next_r][next_c] - heights[this_r][this_c]), _, next_r*self.cols + next_c])
        
        return edges
    

    def findRoot(self, parentDict, node):
        parent = parentDict[node]
        while parent != node:
            node = parent
            parent = parentDict[node]
        return parent

    def unionAndSearchWithKruskal(self, heights, aim):
        parentDict = [_ for _ in range(self.totalNodeNums)]
        size = [1]*self.totalNodeNums
        candidate_edges = self.getEdges(heights)
        if len(candidate_edges) == 0:
            return 0 
        while len(candidate_edges) > 0:
            [edgeweight, startId, endId] =  heapq.heappop(candidate_edges)

            start_parent = self.findRoot(parentDict, startId)
            end_parent = self.findRoot(parentDict, endId)

            if start_parent != end_parent:
                # 没有成环才考虑加入边
                if size[start_parent] < size[end_parent]:
                    start_parent, end_parent = end_parent, start_parent
                parentDict[end_parent] = start_parent 
                size[start_parent] += size[end_parent]  # !!!! 易错点1, 算人头,是把对方麾下的人头都算进来
                if self.findRoot(parentDict, aim) ==  self.findRoot(parentDict, 0):
                    #  # !!!! 易错点2  比较联通是比较他俩祖先是否一样,有可能0的祖先是别人呢!!!!
                    return edgeweight  # 直接返回weight就可以,因为边是从小到大排序,加入这条边,他俩才联通,说明这条边是必须边!
        
    






你可能感兴趣的:(数据结构与刷题,队列,dijkstra,leetcode)