Leetcode 每日一题
题目链接:514. 自由之路
难度: 困难
解题思路: 这道题乍一看,可以选择用动态规划或者BFS来求解。本文使用BFS来进行解答。注意到题中有一个最小的到路径。所以我们可以加入优先队列进行优化,用这个路径花费来对BFS中的队列进行排序,路径长度越小越先出队列。但是这样做还是不够快。会卡在如下样例:

"xrrakuulnczywjs"
"jrlucwzakzussrlckyjjsuwkuarnaluxnyzcnrxxwruyr"

所以我们还需要进行优化。我们需要加入一个visit数组来记录从key的i位置到ring的j位置的最小值(最小花费)。若当前又计算到了这个节点并且这个值还大于等于最小值,我们就抛弃这点,不进入队列。

本题使用的优先队列有个自定义的priority 。 可以直接将当前的花费作为这个优先级。
题解:

import heapq

# 定义优先队列
class PQ:
    def __init__(self):
        self._queue = []
        self._index = 0        

    def queue_push(self, item, priority):
        heapq.heappush(self._queue, (priority, index, item)) # 自定义排序,当前花费越越靠后
        self._index += 1
    
    def queue_pop(self):
        return heapq.heappop(self._queue)[-1]
    
    def is_empty(self):
        return len(self._queue) != 0

class Solution:
    def findRotateSteps(self, ring: str, key: str) -> int:
        lenr = len(ring)
        lenk = len(key)

        def bfs():
            # [key到达的位置, ring到达的位置, 当前花费]
            pq = PQ()
            pq.queue_push([0, 0, 0], 1)
			
			# visit数组表示从key的i位置到ring的j位置的最小值。大于等于最小值的不考虑
            visit = [[] for i in range(lenk)]
            for i in range(lenk):
                for j in range(lenr):
                    visit[i].append(0x3f3f3f3f)


            while pq.is_empty():
                
                node = pq.queue_pop()
                # print(node)
                # 当前遍历到key的最后,找到结果了
                if node[0] == lenk:
                    return node[-1]
                # 顺时针
                for i in range(node[1], lenr):
                    
                    if ring[i] == key[node[0]]:
                        #print(node)
                        priority = node[2] + i - node[1] + 1
                        if visit[node[0]][i] <= priority:
                            continue
                        visit[node[0]][i] = priority

                        pq.queue_push([node[0] + 1, i, priority], priority)

                for i in range(0, node[1]):
                    if ring[i] == key[node[0]]:
                        priority = node[2] + i + (lenr - node[1]) + 1

                        if visit[node[0]][i] <= priority:
                            continue
                        visit[node[0]][i] = priority

                        pq.queue_push([node[0] + 1, i, priority], priority)      

                # 逆时针
                for i in reversed(range(0, node[1])):
                    if ring[i] == key[node[0]]:
                        priority =  node[2] + node[1] - i + 1

                        if visit[node[0]][i] <= priority:
                            continue
                        visit[node[0]][i] = priority

                        pq.queue_push([node[0] + 1, i, priority], priority)

                for i in reversed(range(node[1], lenr)):
                    if ring[i] == key[node[0]]:
                        priority = node[2] + node[1] + (lenr - i) + 1

                        if visit[node[0]][i] <= priority:
                            continue
                        visit[node[0]][i] = priority

                        pq.queue_push([node[0] + 1, i, priority], priority)
        res = bfs()
        return res