# 1320.Minimum-Distance-to-Type-a-Word-Using-Two-Fingers

## 1320. Minimum Distance to Type a Word Using Two Fingers

## 题目地址

<https://leetcode.com/problems/minimum-distance-to-type-a-word-using-two-fingers/>

<https://www.acwing.com/file_system/file/content/whole/index/content/304924/>

## 题目描述

```
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).
```

![](https://assets.leetcode.com/uploads/2020/01/02/leetcode_keyboard.png)

```
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 = 3

Example 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 = 6

Example 3:
Input: word = "NEW"
Output: 3

Example 4:
Input: word = "YEAR"
Output: 7

Constraints:
2 <= word.length <= 300
Each word[i] is an English uppercase letter.
```

## 代码

### Approach #1  3D DP

Let `dp[i][j][k]` be the minimum distance to build the substring from `word` from index `i` untill the end of the word, given that currently the fingers are on positions `j` and `k` respectively.

The transition function will be:

```
dp[i][j][k] = Math.min(dp[i+1][target][k] + distance1, dp[i+1][j][target] + distance2);
```

Then all we need to do is return `dp[0][26][26]`, since both fingers start with no position.

Time: `O(n⋅26⋅26)` && Space: `O(n⋅26⋅26)`

初始化任意两个字母的距离。 设状态 `f(i,j,k)f(i,j,k)` 表示当前完成了前 i 个字母，当前第一根手指在字母 j 上，第二根手指在字母 kk 上的最少步数。 初始时，`f(0,j,k)=0f(0,j,k)=0`，其余为正无穷。初始状态表示了，还没有进行任何操作时，两根手指在任意位置的花费都是 0。 转移时，有两种情况，假设上一次手指的位置为 j 和 k，待移动到的字母为 t。第一种是移动第一根手指，则 `f(i,t,k)=min(f(i,t,k),f(i−1,j,k)+dis(j,t)f(i,t,k)=min(f(i,t,k),f(i−1,j,k)+dis(j,t)` 第二种是移动第二根手指，则 `f(i,j,t)=min(f(i,j,t),f(i−1,j,k)+dis(k,t)f(i,j,t)=min(f(i,j,t),f(i−1,j,k)+dis(k,t)` 最终答案为 `min(f(n,j,k))min(f(n,j,k))`

```java
class Solution {
  public int move(int source, int target) {
    if (source == 26)        return 0;
    int y = source / 6;
    int x = source % 6;
    int y2 = target / 6;
    int x2 = target % 6;
    return Math.abs(x2 - x) + Math.abs(y2 - y);
  }

  public int minimumDistance(String word) {
        int[][][] dp = new int[word.length() + 1][27][27];
    for (int i = word.length() - 1; i >= 0; i--) {
      for (int j = 0; j < 27; j++) {
        for (int k = 0; k < 27; k++) {
          int a = word.charAt(i) - 'A';
          int f1move = move(j, a);
          int f2move = move(k, a);
          dp[i][j][k] = Math.min(dp[i+1][a][k] + f1move, dp[i+1][j][a] + f2move);
        }
      }
    }
    return dp[0][26][26];
  }
}
```

### Approach #2 1D DP

```java
public int minimumDistance(String word) {
  int dp[] = new int[26], res = 0, save = 0, n = word.length();
  for (int i = 0; i < n - 1; i++) {
    int b = word.charAt(i) - 'A';
    int c = word.charAt(i + 1) - 'A';
    for (int a = 0; a < 26; a++) {
      dp[b] = Math.max(dp[b], dp[a] + d(b, c) - d(a, c));
    }
    save = Math.max(save, dp[b]);
    res += d(b, c);
  }

  return res - save;
}

private int d(int a, int b) {
  return Math.abs(a / 6 - b / 6) + Math.abs(a % 6 - b % 6);
}
```
