Leetcode 1307. 口算难题

本文探讨了一种解决字符替换谜题的有效算法。通过预处理字符权重和限制,避免了直接枚举导致的超时问题。算法巧妙地利用了DFS深度优先搜索,确保了首字符不为0的规则,成功找出满足等式的字符到数字的映射。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题解

因为一共只有10种可能的数字[0-9],所以等式中包含的所有的字符最多包含10种,我们只需要枚举每一种字符对应到每一种数字,得到满足条件的那一个即可,但是要注意,首字符不能为0。
思路非常的简单,但是也要注意,处理不当可能会超时。我们如果直接枚举每一种字符可能对应的数字,然后再根据等式计算结果,这样非常可能超时。可以先进行预处理,求出给定的所有串中出现的字符的出现的次数和出现的位置代表的数字的和,最终将这些和加上就能判断正确结果。最后这一点不好描述,但是代码非常清晰,可以查看代码

// 每一种字符出现的权重
int[] weights = new int[26];
// 哪些字符不能为0
boolean[] notZero = new boolean[26];

public boolean isSolvable(String[] words, String result) {
	// 标记字符是否出现过
    boolean[] has = new boolean[26];
    for (int i = 0; i < words.length; i++) {
        int p = 1;
        for (int j = words[i].length() - 1; j >= 0; j--) {
            has[words[i].charAt(j) - 'A'] = true;
            weights[words[i].charAt(j) - 'A'] += p;
            p *= 10;
        }
        notZero[words[i].charAt(0) - 'A'] = true;
    }
    int p = 1;
    for (int i = result.length() - 1; i >= 0; i--) {
        has[result.charAt(i) - 'A'] = true;
        // 注意这里是负号!!因为这是等式的右边
        weights[result.charAt(i) - 'A'] -= p;
        p *= 10;
    }
    notZero[result.charAt(0) - 'A'] = true;
    List<Integer> list = new ArrayList<>();
    // 获取到所有出现的字符
    for (int i = 0; i < 26; i++) {
        if (has[i]) {
            list.add(i);
        }
    }
    Integer[] ints = list.toArray(new Integer[0]);
    return dfs(ints, new boolean[10], 0, 0);
}

public boolean dfs(Integer[] chars, boolean[] vis, int index, int sum) {
    if (index == chars.length) {
        return sum == 0;
    }
    for (int i = 0; i < 10; i++) {
        if (!vis[i]) {
            if (notZero[chars[index]] && i == 0) {
                continue;
            }
            vis[i] = true;
            if (dfs(chars, vis, index + 1, sum + i * weights[chars[index]])) {
                return true;
            }
            vis[i] = false;
        }
    }
    return false;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值