思路一(错误):贪心
此题要做出来,只需要知道,当前字母到下一个字母最短位置。由于字母可以重复,每次选最近的字母的贪心策略可以产生局部最优,但全局的步数并不是最少的。
class Solution:
def get_step(self, idx1, idx2, length):
min0, max0 = min(idx1, idx2), max(idx1, idx2)
return min(max0-min0, length-max0+min0)
def findRotateSteps(self, ring: str, key: str) -> int:
MAX = 2000
char2pos = {}
for i in range(len(ring)):
char = ring[i]
if char in char2pos:
char2pos[char].append(i)
else:
char2pos[char] = [i]
total_steps, current_pos = 0, 0
for char in key:
min_step, min_pos = MAX, 0
for pos in char2pos[char]:
step = self.get_step(pos, current_pos, len(ring))
if step < min_step:
min_step = step
min_pos = pos
current_pos = min_pos
total_steps += min_step + 1
return total_steps
思路二(正确):动态规划
通过上一种思路,可以想到维特比算法是一种很好的策略。在每一层根据上一层所有点的最优解,可以得到每个点的最优解。代码如下:
class Solution:
def get_step(self, idx1, idx2, length):
min0, max0 = min(idx1, idx2), max(idx1, idx2)
return min(max0-min0, length-max0+min0)
def findRotateSteps(self, ring: str, key: str) -> int:
MAX = 2000
char2pos = {}
for i in range(len(ring)):
char = ring[i]
if char in char2pos:
char2pos[char].append(i)
else:
char2pos[char] = [i]
posNsteps = [(0,0)]
for char in key:
new_list = []
for end_pos in char2pos[char]:
min_step = MAX
for tup in posNsteps:
start_pos, prev_step = tup
step = self.get_step(start_pos, end_pos, len(ring))
if prev_step + step < min_step:
min_step = step + prev_step + 1
new_list.append((end_pos, min_step))
posNsteps = new_list
minx = MAX
for tup in posNsteps:
_, step = tup
minx = min(minx, step)
return minx