---
# System prepended metadata

title: 2746. Decremental String Concatenation
tags: [Leetcode, Dynamic Programming, Medium]

---

Link: https://leetcode.com/problems/decremental-string-concatenation/description/
## 思路
三维dp
dp[i][j][k]表示把i后面包含i的所有word逐个加在 以j开头 以k结尾的string上得到的string的最短的长度
python里面用了```@lru_cache(None)```就会自动把dp array存下来
#### 优化
参考[这里](https://leetcode.com/problems/decremental-string-concatenation/solutions/3677609/dp/)
由于我们知道每个dfs在运算的时候 拿到的start和end肯定有一个来自上一个字符串
因此我们只需要记录另一个字符是什么 以及他在start还是end即可
## Code
Python $O(26*26n)$
```python=
class Solution:
    def minimizeConcatenatedLength(self, words: List[str]) -> int:
        @lru_cache(None)
        def dfs(idx, start, end):
            if idx>=len(words): return 0
            addToBack = dfs(idx+1, start, ord(words[idx][-1])-ord('a'))
            if (ord(words[idx][0])-ord('a'))==end: addToBack -= 1

            addToFront = dfs(idx+1, ord(words[idx][0])-ord('a'), end)
            if (ord(words[idx][-1])-ord('a'))==start: addToFront -= 1

            return min(addToBack, addToFront)+len(words[idx])

        return len(words[0])+dfs(1, ord(words[0][0])-ord('a'), ord(words[0][-1])-ord('a'))
```
Java $O(26*26n)$
```java=
class Solution {
    public int minimizeConcatenatedLength(String[] words) {
        int[][][] dp = new int[1001][26][26];
        return words[0].length()+dfs(1, words[0].charAt(0)-'a', words[0].charAt(words[0].length()-1)-'a', words, dp);
    }
    public int dfs(int idx, int start, int end, String[] words, int[][][] dp){
        if (idx>=words.length) return 0;
        if (dp[idx][start][end]==0){
            int n = words[idx].length();
            int addToBack = dfs(idx+1, start, words[idx].charAt(n-1)-'a', words, dp);
            if((words[idx].charAt(0)-'a')==end) addToBack -= 1;

            int addToFront = dfs(idx+1, words[idx].charAt(0)-'a', end, words, dp);
            if((words[idx].charAt(n-1)-'a')==start) addToFront -= 1;

            dp[idx][start][end] = Math.min(addToBack, addToFront)+words[idx].length();
        }
        return dp[idx][start][end];
    }
}
```
Java $O(26*2*n)$
```java=
class Solution {
    public int minimizeConcatenatedLength(String[] words) {
        int[][][] dp = new int[1001][26][2];
        return words[0].length()+dfs(1, words[0].charAt(0)-'a', true, words, dp);
    }
    public int dfs(int idx, int ch, boolean left, String[] words, int[][][] dp){
        if (idx>=words.length) return 0;
        if (dp[idx][ch][left?1:0]==0){
            int n = words[idx].length();
            int start = left ? ch : (words[idx-1].charAt(0)-'a');
            int end = !left ? ch : (words[idx-1].charAt(words[idx-1].length()-1)-'a');

            int addToBack = dfs(idx+1, start, true, words, dp);
            if((words[idx].charAt(0)-'a')==end) addToBack -= 1;

            int addToFront = dfs(idx+1, end, false, words, dp);
            if((words[idx].charAt(n-1)-'a')==start) addToFront -= 1;

            dp[idx][ch][left?1:0] = Math.min(addToBack, addToFront)+words[idx].length();
        }
        return dp[idx][ch][left?1:0];
    }
}
```