校招算法笔面试 | 校招笔面试真题-字符串交错组成

题目

题目链接

解题思路

这是一个字符串交错组成问题,可以使用动态规划求解。关键点:

  1. 动态规划定义

    • d p [ i ] [ j ] dp[i][j] dp[i][j] 表示 A A A 的前 i i i 个字符和 B B B 的前 j j j 个字符是否能交错组成 C C C 的前 i + j i+j i+j 个字符
    • i i i 范围: [ 0 , n ] [0,n] [0,n] j j j 范围: [ 0 , m ] [0,m] [0,m]
  2. 状态转移

    • 如果 A [ i − 1 ] = = C [ i + j − 1 ] A[i-1] == C[i+j-1] A[i1]==C[i+j1] d p [ i ] [ j ] ∣ = d p [ i − 1 ] [ j ] dp[i][j] |= dp[i-1][j] dp[i][j]=dp[i1][j]
    • 如果 B [ j − 1 ] = = C [ i + j − 1 ] B[j-1] == C[i+j-1] B[j1]==C[i+j1] d p [ i ] [ j ] ∣ = d p [ i ] [ j − 1 ] dp[i][j] |= dp[i][j-1] dp[i][j]=dp[i][j1]
  3. 边界条件

    • d p [ 0 ] [ 0 ] = t r u e dp[0][0] = true dp[0][0]=true
    • 第一行:只用 B B B 串匹配
    • 第一列:只用 A A A 串匹配

代码

class Mixture {
public:
    bool chkMixture(string A, int n, string B, int m, string C, int v) {
        if(n + m != v) return false;
        
        vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
        dp[0][0] = 1;
        
        // 初始化第一列
        for(int i = 1; i <= n; i++) {
            if(A[i-1] == C[i-1]) {
                dp[i][0] = dp[i-1][0];
            }
        }
        
        // 初始化第一行
        for(int j = 1; j <= m; j++) {
            if(B[j-1] == C[j-1]) {
                dp[0][j] = dp[0][j-1];
            }
        }
        
        // 填充dp表
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(A[i-1] == C[i+j-1]) {
                    dp[i][j] |= dp[i-1][j];
                }
                if(B[j-1] == C[i+j-1]) {
                    dp[i][j] |= dp[i][j-1];
                }
            }
        }
        
        return dp[n][m];
    }
};
public class Mixture {
    public boolean chkMixture(String A, int n, String B, int m, String C, int v) {
        if(n + m != v) return false;
        
        boolean[][] dp = new boolean[n + 1][m + 1];
        dp[0][0] = true;
        
        // 初始化第一列
        for(int i = 1; i <= n; i++) {
            if(A.charAt(i-1) == C.charAt(i-1)) {
                dp[i][0] = dp[i-1][0];
            }
        }
        
        // 初始化第一行
        for(int j = 1; j <= m; j++) {
            if(B.charAt(j-1) == C.charAt(j-1)) {
                dp[0][j] = dp[0][j-1];
            }
        }
        
        // 填充dp表
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(A.charAt(i-1) == C.charAt(i+j-1)) {
                    dp[i][j] |= dp[i-1][j];
                }
                if(B.charAt(j-1) == C.charAt(i+j-1)) {
                    dp[i][j] |= dp[i][j-1];
                }
            }
        }
        
        return dp[n][m];
    }
}
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*-

class Mixture:
    def chkMixture(self, A, n, B, m, C, v):
        # Check length first
        if n + m != v:
            print("Length not match")
            return False
            
        dp = [[False] * (m + 1) for _ in xrange(n + 1)]
        dp[0][0] = True
        
        # Initialize first column
        for i in xrange(1, n + 1):
            if A[i-1] == C[i-1]:
                dp[i][0] = dp[i-1][0]
                print("Match A[%d]=%s with C[%d]=%s" % (i-1, A[i-1], i-1, C[i-1]))
        
        # Initialize first row
        for j in xrange(1, m + 1):
            if B[j-1] == C[j-1]:
                dp[0][j] = dp[0][j-1]
                print("Match B[%d]=%s with C[%d]=%s" % (j-1, B[j-1], j-1, C[j-1]))
        
        # Fill dp table
        for i in xrange(1, n + 1):
            for j in xrange(1, m + 1):
                if A[i-1] == C[i+j-1]:
                    dp[i][j] |= dp[i-1][j]
                    print("Match A[%d]=%s with C[%d]=%s" % (i-1, A[i-1], i+j-1, C[i+j-1]))
                if B[j-1] == C[i+j-1]:
                    dp[i][j] |= dp[i][j-1]
                    print("Match B[%d]=%s with C[%d]=%s" % (j-1, B[j-1], i+j-1, C[i+j-1]))
        
        print("Final result:", dp[n][m])
        return dp[n][m]

算法及复杂度

  • 算法:动态规划
  • 时间复杂度: O ( n m ) \mathcal{O(nm)} O(nm),需要填充整个 d p dp dp
  • 空间复杂度: O ( n m ) \mathcal{O(nm)} O(nm),需要二维 d p dp dp 数组
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值