Skip to content

1055. Shortest Way to Form String 👍

Approach 1: Greedy

  • Time: $O(|\texttt{source}||\texttt{target}|)$
  • Space: $O(1)$, $O(26 \cdot |\texttt{source}|)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
 public:
  int shortestWay(string source, string target) {
    int ans = 0;

    for (int i = 0; i < target.length();) {
      const int prevIndex = i;
      for (int j = 0; j < source.length(); ++j)
        if (i < target.length() && source[j] == target[i])
          ++i;
      // All chars in source didn't match target[i]
      if (i == prevIndex)
        return -1;
      ++ans;
    }

    return ans;
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Solution {
  public int shortestWay(String source, String target) {
    int ans = 0;

    for (int i = 0; i < target.length();) {
      final int prevIndex = i;
      for (int j = 0; j < source.length(); ++j)
        if (i < target.length() && source.charAt(j) == target.charAt(i))
          ++i;
      // All chars in source didn't match target[i]
      if (i == prevIndex)
        return -1;
      ++ans;
    }

    return ans;
  }
}

Approach 2: DP

  • Time: $O(|\texttt{source}| + |\texttt{target}|)$
  • Space: undefined
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
 public:
  int shortestWay(string source, string target) {
    const int m = source.length();
    const int n = target.length();
    // dp[i][c] := the earliest index >= i s.t. source[index] = c
    // dp[i][c] := -1 if c isn't in the source
    vector<vector<int>> dp(m, vector<int>(26, -1));

    dp[m - 1][source[m - 1] - 'a'] = m - 1;
    for (int i = m - 2; i >= 0; --i) {
      dp[i] = dp[i + 1];
      dp[i][source[i] - 'a'] = i;
    }

    int ans = 0;
    int i = 0;  // source's index

    for (const char c : target) {
      if (dp[0][c - 'a'] == -1)
        return -1;
      // If there are no c's left in source that occur more than i times but
      // there are c's from earlier in the subsequence, add 1 to subsequence
      // count and reset source's index to 0.
      if (dp[i][c - 'a'] == -1) {
        ++ans;
        i = 0;
      }
      // Continue taking letters from the subsequence.
      i = dp[i][c - 'a'] + 1;
      if (i == m) {
        ++ans;
        i = 0;
      }
    }

    return ans + (i == 0 ? 0 : 1);
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Solution {
  public int shortestWay(String source, String target) {
    final int m = source.length();
    final int n = target.length();
    // dp[i][c] := the earliest index >= i s.t. source[index] = c
    // dp[i][c] := -1 if c isn't in the source
    int[][] dp = new int[m][26];

    Arrays.stream(dp).forEach(A -> Arrays.fill(A, -1));

    dp[m - 1][source.charAt(m - 1) - 'a'] = m - 1;
    for (int i = m - 2; i >= 0; --i) {
      dp[i] = dp[i + 1].clone();
      dp[i][source.charAt(i) - 'a'] = i;
    }

    int ans = 0;
    int i = 0; // source's index

    for (final char c : target.toCharArray()) {
      if (dp[0][c - 'a'] == -1)
        return -1;
      // If there are no c's left in source that occur more than i times but
      // there are c's from earlier in the subsequence, add 1 to subsequence
      // count and reset source's index to 0.
      if (dp[i][c - 'a'] == -1) {
        ++ans;
        i = 0;
      }
      // Continue taking letters from the subsequence.
      i = dp[i][c - 'a'] + 1;
      if (i == m) {
        ++ans;
        i = 0;
      }
    }

    return ans + (i == 0 ? 0 : 1);
  }
}