寻找最匹配士兵 | 豆包MarsCode AI 刷题

232 阅读3分钟

题解:寻找最匹配士兵

题目分析

我们需要为目标任务找到一个士兵性格密码,匹配规则分为以下几步:

  1. 每个性格密码有 (M) 维。
  2. 每维的匹配程度通过字母距离计算,差异越小越匹配。
  3. 如果某一维性格不兼容(如 AE, BD 等),该士兵直接排除。
  4. 找到所有符合条件且差异最小的士兵密码。

代码实现

以下是实现代码,并带有详细讲解。

import java.util.*;

public class Main {
    // 计算两个字符的差异值
    private static int dist(char x, char y) {
        List<String> incompatibility = Arrays.asList("AE", "BD", "CE", "BE");
        // 构造不兼容对
        String pair = "" + x + y;
        String reversePair = "" + y + x;

        // 如果是无效组合,返回无穷大
        if (incompatibility.contains(pair) || incompatibility.contains(reversePair)) {
            return Integer.MAX_VALUE;
        }

        // 否则返回差异值
        return Math.abs(x - y);
    }

    public static String solution(int m, int n, String target, String[] array) {
        // 最小差异值记录
        int bestDist = Integer.MAX_VALUE;
        List<String> bestMatches = new ArrayList<>();

        for (String s : array) {
            int totalDist = 0;
            boolean isValid = true; // 判断当前士兵是否有效

            for (int i = 0; i < m; i++) {
                int currDist = dist(target.charAt(i), s.charAt(i));

                // 如果当前维度不匹配,直接退出
                if (currDist == Integer.MAX_VALUE) {
                    isValid = false;
                    break;
                }

                totalDist += currDist;
            }

            // 如果当前士兵有效,比较差异值
            if (isValid) {
                if (totalDist < bestDist) {
                    bestDist = totalDist;
                    bestMatches.clear();
                    bestMatches.add(s);
                } else if (totalDist == bestDist) {
                    bestMatches.add(s);
                }
            }
        }

        // 如果没有找到合适的士兵
        if (bestMatches.isEmpty()) {
            return "None";
        }

        // 返回所有最优士兵密码,以空格分隔
        return String.join(" ", bestMatches);
    }

    public static void main(String[] args) {
        // 测试样例
        String[] matrix1 = {"AAAAAA", "BBBBBB", "ABDDEB"};
        System.out.println(solution(6, 3, "ABCDEA", matrix1)); // 输出:ABDDEB

        String[] matrix2 = {"ABCDE", "BCDEA", "ABDCE", "EDCBA"};
        System.out.println(solution(5, 4, "ABCED", matrix2)); // 输出:ABCDE

        String[] matrix3 = {"ACDC", "BBDC", "EBCB", "BBBB"};
        System.out.println(solution(4, 4, "AEBC", matrix3)); // 输出:None
    }
}

代码讲解

  1. dist方法

    • 接收两个字符,判断是否存在不兼容关系。
    • 如果不兼容,返回无穷大 (Integer.MAX_VALUE);否则返回字母差值。
  2. 遍历候选密码数组

    • 对于每个候选密码,逐维度计算差异值。
    • 如果某一维度不匹配,直接跳过该密码。
  3. 记录最优解

    • 维护当前最小差异值 bestDist 和对应的最优密码列表 bestMatches
    • 如果发现更小的差异值,更新结果;如果差异值相同,将密码加入列表。
  4. 结果拼接

    • 如果没有符合条件的密码,返回 "None"
    • 否则将最优密码列表用空格拼接返回。

改进方案

为了让代码更整洁,可以将兼容性检查逻辑与差异值计算逻辑分离,同时减少 StringBuilder 操作。

改进后的dist方法:
private static final Set<String> INCOMPATIBILITY = new HashSet<>(Arrays.asList("AE", "BD", "CE", "BE"));

private static int dist(char x, char y) {
    if (x == y) return 0;
    if (INCOMPATIBILITY.contains("" + x + y) || INCOMPATIBILITY.contains("" + y + x)) {
        return Integer.MAX_VALUE;
    }
    return Math.abs(x - y);
}
改进后的匹配逻辑:
boolean isValid = true;
for (int i = 0; i < m && isValid; i++) {
    int currDist = dist(target.charAt(i), s.charAt(i));
    if (currDist == Integer.MAX_VALUE) isValid = false;
    else totalDist += currDist;
}
使用String.join优化拼接:
return bestMatches.isEmpty() ? "None" : String.join(" ", bestMatches);
优化点总结
  1. 使用 Set 加速不兼容对的查找。
  2. 将拼接逻辑抽离为标准库函数。
  3. 利用条件短路减少冗余代码,提升可读性。

以上改进使代码结构更清晰,同时提升了性能和可维护性。