【leetcode】1320. Minimum Distance to Type a Word Using Two Fingers
题目如下:
You have a keyboard layout as shown above in the XY plane, where each English uppercase letter is located at some coordinate, for example, the letter A is located at coordinate (0,0), the letter B is located at coordinate (0,1), the letter P is located at coordinate (2,3) and the letter Z is located at coordinate (4,1).
Given the string
word
, return the minimum total distance to type such string using only two fingers. The distance between coordinates (x1,y1) and (x2,y2) is |x1 - x2| + |y1 - y2|.Note that the initial positions of your two fingers are considered free so don't count towards your total distance, also your two fingers do not have to start at the first letter or the first two letters.
Example 1:
Input: word = "CAKE" Output: 3 Explanation: Using two fingers, one optimal way to type "CAKE" is: Finger 1 on letter 'C' -> cost = 0 Finger 1 on letter 'A' -> cost = Distance from letter 'C' to letter 'A' = 2 Finger 2 on letter 'K' -> cost = 0 Finger 2 on letter 'E' -> cost = Distance from letter 'K' to letter 'E' = 1 Total distance = 3Example 2:
Input: word = "HAPPY" Output: 6 Explanation: Using two fingers, one optimal way to type "HAPPY" is: Finger 1 on letter 'H' -> cost = 0 Finger 1 on letter 'A' -> cost = Distance from letter 'H' to letter 'A' = 2 Finger 2 on letter 'P' -> cost = 0 Finger 2 on letter 'P' -> cost = Distance from letter 'P' to letter 'P' = 0 Finger 1 on letter 'Y' -> cost = Distance from letter 'A' to letter 'Y' = 4 Total distance = 6Example 3:
Input: word = "NEW" Output: 3Example 4:
Input: word = "YEAR" Output: 7Constraints:
2 <= word.length <= 300
- Each
word[i]
is an English uppercase letter.
解题思路:首先把A-Z分别用0~25下标来代替,记dp[i][j][k] 为输入完第i个字符后左手在第j个位置,右手在第k个位置的时候移动的次数最小。这里只需要和dp[i-1]建立状态转移方程,可以分为以下四种情况:
1. word[i]和word[i-1]都是左手输入的,那么左手一定是从word[i-1]的索引位置移动到word[i]的索引位置,而右手可以处在任意索引位置j上面, 有 dp[i][inx][j] = min(dp[i][inx][j], dp[i-1][pervious_inx][j] + calcDis(pervious_inx,inx)) ; 其中inx为第word[i]个字符的索引,pervious_inx是word[i-1]的索引,calcDis 计算的是从 pervious_inx到 inx需要移动的距离。
2.word[i]是左手输入并且word[i-1]是右手输入,那么右手还处于word[i-1]的索引位置,而左手可能从任意的索引位置j移动到 word[i]索引位置,有 dp[i][inx][pervious_inx] = min(dp[i][inx][pervious_inx], dp[i-1][j][pervious_inx] + calcDis(j, inx)) 。
3.word[i]是右手输入并且word[i-1]是左手输入,有dp[i][pervious_inx][inx] = min(dp[i][pervious_inx][inx], dp[i-1][pervious_inx][j] + calcDis(j, inx)) 。
4.word[i]和word[i-1]都是右手输入的,有 dp[i][j][inx] = min(dp[i][j][inx], dp[i-1][j][pervious_inx] + calcDis(pervious_inx,inx))
代码如下:
class Solution(object): def minimumDistance(self, word): """ :type word: str :rtype: int """ def getInx(char): return ord(char) - ord('A') def calcDis(inx1,inx2): if inx1 / 6 == inx2 / 6: return abs(inx2 - inx1) dis = abs(inx1 / 6 - inx2 / 6) min_inx = min(inx1,inx2) max_inx = max(inx1,inx2) min_inx += dis * 6 return dis + abs(max_inx - min_inx) dp = [[[float('inf')] * 26 for _ in range(26)] for _ in word] for k in range(26): # the first letter input by left hand dp[0][getInx(word[0])][k] = 0 # the first letter input by right hand #print k,getInx(word[0]) dp[0][k][getInx(word[0])] = 0 res = float('inf') for i in range(1,len(word)): for j in range(26): inx = getInx(word[i]) pervious_inx = getInx(word[i-1]) # input via left hand,pervious is left too dp[i][inx][j] = min(dp[i][inx][j], dp[i-1][pervious_inx][j] + calcDis(pervious_inx,inx)) # input via left hand,pervious is right dp[i][inx][pervious_inx] = min(dp[i][inx][pervious_inx], dp[i-1][j][pervious_inx] + calcDis(j, inx)) # input via right hand,pervious is left dp[i][pervious_inx][inx] = min(dp[i][pervious_inx][inx], dp[i-1][pervious_inx][j] + calcDis(j, inx)) # input via right hand,pervious is right too dp[i][j][inx] = min(dp[i][j][inx], dp[i-1][j][pervious_inx] + calcDis(pervious_inx,inx)) last_inx = getInx(word[-1]) for i in range(26): res = min(res,dp[-1][last_inx][i]) res = min(res,dp[-1][i][last_inx]) #print dp return res