【递归算法】字母大小写全排列

文章摘要:

  • 本文解析LeetCode题目《字母大小写全排列》,要求生成给定字符串所有字母大小写组合。通过决策树模型展示递归过程:遍历字符串,遇到字母时分别添加大小写形式,数字则直接添加。使用回溯法维护全局变量ret(结果集)和path(当前路径),递归出口为遍历完字符串时保存结果。提供两种Java实现:版本一显式处理大小写转换,版本二封装转换函数。两种方案均通过回溯恢复现场确保状态正确,最终返回所有可能组合。

文章目录

题目链接

一、题目解析

题目会给出一个字符串,让我们将字符串里的字母转换大小写,找出所有的组合。

例如示例 1 给出的字符串 s = "a1b2",我们需要返回 [ "a1b2", "a1B2", "A1b2", "A1B2" ]。

二、算法原理 + 代码实现

决策树

我们按照暴搜的普遍思路:依次枚举画出决策树。

根据示例 1:

从左往右遍历字符串,遇到字母就选择添加大写还是小写,遇到数字就直接添加,枚举每一种情况。

决策树如下:

全局变量

这里依然是两个全局变量:ret 记录结果、path 记录路径。

dfs 函数

函数头

由于我们是遍历字符串,要将 s 作为参数,而且是通过递归遍历的,因此需要知道下标 pos。

Java 复制代码
dfs(String s, int pos);

函数体

考虑每一次递归所做的事情,那就是遇到字母就考虑大小写,而遇到数字就无需考虑直接添加。

Java 复制代码
if (字母的判定条件) {
	// 先添加小写
	// 再添加大写
} else {
	// 添加数字
}

注意,每一次添加完递归回来后都要考虑恢复现场。

除了依次添加大小写,也可以直接通过一个函数完成大小写的转换:

Java 复制代码
if (字母的判定条件) {
	// 转换后添加字母
}
// 添加数字

细节问题

回溯

回溯时的恢复现场操作是将 path 的最后元素删掉。

剪枝

本题是穷举了所有情况,因此不涉及剪枝操作。

递归出口

当遍历到字符串 s 的最后字符就需要更新结果了,然后返回即可。

代码实现

版本一

Java 复制代码
class Solution {
    List<String> ret;
    StringBuilder path;

    public List<String> letterCasePermutation(String s) {
        ret = new ArrayList<>();
        path = new StringBuilder();

        dfs(s, 0);
        return ret;
    }

    private void dfs(String s, int pos) {
        // 递归出口
        if (pos == s.length()) {
            ret.add(path.toString());
            return;
        }

        char ch = s.charAt(pos);
        if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
            // 是字母,需要转换大小写
            // 添加小写字母
            if (ch >= 'A' && ch <= 'Z') path.append(ch += 32);
            else path.append(ch);
            dfs(s, pos + 1);
            path.deleteCharAt(path.length() - 1); // 回溯时恢复现场

            // 添加大写字母
            if (ch >= 'a' && ch <= 'z') path.append(ch -= 32);
            else path.append(ch);
            dfs(s, pos + 1);
            path.deleteCharAt(path.length() - 1); // 回溯时恢复现场
        } else {
            // 是数字,直接添加
            path.append(ch);
            dfs(s, pos + 1);
            path.deleteCharAt(path.length() - 1); // 回溯时恢复现场
        }
    }
}

版本二

Java 复制代码
class Solution {
    List<String> ret;
    StringBuilder path;
    
    public List<String> letterCasePermutation(String s) {
        ret = new ArrayList<>();
        path = new StringBuilder();
        
        dfs(s, 0);
        return ret;
    }

    private void dfs(String s, int pos) {
        // 递归出口
        if (pos == s.length()) {
            ret.add(path.toString());
            return;
        }
        
        char ch = s.charAt(pos);
        if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {
            // 是字母,需要转换大小写
            path.append(deal(ch));
            dfs(s, pos + 1);
            path.deleteCharAt(path.length() - 1); // 回溯时恢复现场
        }
        
        // 是数字,不用转换直接添加
        path.append(ch);
        dfs(s, pos + 1);
        path.deleteCharAt(path.length() - 1); // 回溯时恢复现场
    }

    private char deal(char ch) {
        if (ch >= 'a' && ch <= 'z') return ch -= 32;
        else return ch += 32;
    }
}

文章到这里就告一段落啦,若有错误请尽管指出~

相关推荐
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ7 小时前
通过java后端代码来实现给word内容补充格式文本内容控件,以及 设置控件的标记和标题
java·c#·word
刀法如飞8 小时前
TypeScript 数组去重的 20 种实现方式,哪一种你还不知道?
前端·javascript·算法
無限進步D8 小时前
Java 面向对象高级 接口
java·开发语言
逸Y 仙X9 小时前
文章二十七:ElasticSearch ES查询模板(Search Template)高效复用实战
java·大数据·数据库·elasticsearch·搜索引擎·全文检索
二哈赛车手9 小时前
新人笔记---Spring AI的Advisor以及其底层机制讲解(涉及源码),包含一些遇见的Spring AI的Advisor缺陷问题的解决方案
java·人工智能·spring boot·笔记·spring
sali-tec9 小时前
C# 基于OpenCv的视觉工作流-章66-直线夹角
图像处理·人工智能·opencv·算法·计算机视觉
AC赳赳老秦9 小时前
接口测试自动化:用 OpenClaw 对接 Postman,实现批量回归测试、测试报告自动生成与推送
java·人工智能·python·算法·elasticsearch·deepseek·openclaw
两年半的个人练习生^_^9 小时前
Java日志框架和使用、日志记录规范
java·开发语言·开发规范
_风满楼9 小时前
TDD实战-会议室冲突检测的红绿重构循环
前端·javascript·算法