下面我直接给你可直接提交的 Java 版标准题解,思路清晰、注释完整,对应 LeetCode 1639. Number of Ways to Form a Target String Given a Dictionary。
 
题目大意
 
- 给你一个字符串数组  words ,每个字符串长度相同。
- 你要按列选字符,拼成  target 。
- 选第 1 个字符必须在第 1 列,第 2 个字符必须在第 2 列,依此类推,列不能回头用。
- 求有多少种方案,答案对  1e9+7  取模。
 
思路(标准 DP)
 
1. 预处理:统计每一列,每个字符出现多少次。
2. DP 定义:-  dp[i][j] :用前  j  列,拼出  target  前  i  个字符的方案数。
3. 转移:- 不选第 j 列: dp[i][j] += dp[i][j-1] 
- 选第 j 列(匹配 target[i-1]): dp[i][j] += dp[i-1][j-1] * cnt[j-1][c] 
4. 答案: dp[len(target)][len(words[0])] 
 
Java 代码(可直接提交)
 
java   
import java.util.*;

class Solution {
    public int numWays(String[] words, String target) {
        final int MOD = 1000000007;
        int n = words[0].length();   // 列数
        int m = target.length();     // target 长度
        char[] t = target.toCharArray();
        
        // 预处理:cnt[j][c] = 第 j 列字符 c 的出现次数
        long[][] cnt = new long[n][26];
        for (String w : words) {
            for (int j = 0; j < n; j++) {
                cnt[j][w.charAt(j) - 'a']++;
            }
        }
        
        // dp[i][j] = 前 j 列,拼 target 前 i 个字符的方案数
        long[][] dp = new long[m + 1][n + 1];
        // 边界:拼 0 个字符,不管多少列都是 1 种方案
        for (int j = 0; j <= n; j++) {
            dp[0][j] = 1;
        }
        
        for (int i = 1; i <= m; i++) {
            char c = t[i - 1];
            for (int j = 1; j <= n; j++) {
                // 不选第 j 列
                dp[i][j] = dp[i][j - 1];
                
                // 选第 j 列
                long add = dp[i - 1][j - 1] * cnt[j - 1][c - 'a'];
                dp[i][j] = (dp[i][j] + add) % MOD;
            }
        }
        
        return (int) (dp[m][n] % MOD);
    }
}
 
 
空间优化版(可选)
 
把二维 DP 压成一维,从后往前更新避免覆盖:
 
java   
class Solution {
    public int numWays(String[] words, String target) {
        final int MOD = 1000000007;
        int n = words[0].length();
        int m = target.length();
        char[] t = target.toCharArray();
        
        long[][] cnt = new long[n][26];
        for (String w : words) {
            for (int j = 0; j < n; j++) {
                cnt[j][w.charAt(j) - 'a']++;
            }
        }
        
        long[] dp = new long[m + 1];
        dp[0] = 1;
        
        for (int j = 0; j < n; j++) {
            // 从后往前,避免覆盖
            for (int i = m; i >= 1; i--) {
                char c = t[i - 1];
                dp[i] = (dp[i] + dp[i - 1] * cnt[j][c - 'a']) % MOD;
            }
        }
        
        return (int) dp[m];
    }
}
 
 
 
 
如果你愿意,我可以顺便给你写 C++ / Python / Go / TypeScript 版本,或者把这道题的 DP 转移过程用例子一步步演算给你看,方便彻底理解。

 

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐