回溯算法算法

字符串拼接

2025-10-23  本文已影响0人  何以解君愁

 给定M (0<M<=30)个字符(a-z),从中取出任意字符(每个字符只能用一次)拼接成长度为N (0<N<=5)的字符串,要求相同的字符不能相邻,计算出给定的字符列表能拼接出多少种满足条件的字符串,输入非法或者无法拼接出满足条件的字符串则返回0。
 输入描述:给定的字符列表和结果字符串长度,中间使用空格(" ")拼接
 输出描述:满足条件的字符串个数

import java.util.*;

public class Main {
    static int res = 0;
    static boolean[] used;
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int length = sc.nextInt();
        boolean check = false;
        
        // 检查输入字符是否合法(a-z)
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) < 'a' || s.charAt(i) > 'z') {
                check = true;
                break;
            }
        }
        
        if (length > s.length() || check || length <= 0) {
            System.out.print("0");
        } else {
            used = new boolean[s.length()];
            char[] chars = s.toCharArray();
            Arrays.sort(chars); // 排序便于去重
            backtrack(chars, new StringBuilder(), length);
            System.out.print(res);
        }
    }
    
    public static void backtrack(char[] chars, StringBuilder path, int length) {
        // 终止条件:当前路径长度等于目标长度
        if (path.length() == length) {
            res++;
            return;
        }
        
        for (int i = 0; i < chars.length; i++) {
            // 跳过已使用的字符
            if (used[i]) {
                continue;
            }
            // 去重剪枝:跳过相同字符的前一个未使用字符
            if (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]) {
                continue;
            }
            // 相邻字符相同剪枝:检查当前字符是否与路径最后一个字符相同
            if (path.length() > 0 && path.charAt(path.length() - 1) == chars[i]) {
                continue;
            }
            // 做出选择
            used[i] = true;
            path.append(chars[i]);
            // 递归回溯
            backtrack(chars, path, length);
            // 撤销选择
            used[i] = false;
            path.deleteCharAt(path.length() - 1);
        }
    }
}
上一篇 下一篇

猜你喜欢

热点阅读