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

文章摘要:

  • 本文解析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;
    }
}

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

完

相关推荐
盘古开天16665 分钟前
PPO算法代码实战(三):PyTorch从零实现PPO求解CartPole
人工智能·pytorch·算法
yyy(十一月限定版)5 分钟前
CF2138A Cake Assignment
算法
奋发向前wcx15 分钟前
CSP-J复赛模拟赛1 王晨旭补题 2026.10.2
java·开发语言
xqqxqxxq22 分钟前
LeetCode Hot100 矩阵专题题解笔记
笔记·leetcode·矩阵
盘古开天166627 分钟前
PPO算法原理详解(下):Clip机制深入剖析与实践指南
人工智能·算法·机器学习
卓怡学长27 分钟前
w192基于springboot“考研情报站”微信小程序设计与实现
java·spring boot·spring·微信小程序·intellij-idea
wuminyu38 分钟前
JEP491中synchronized关键字引发的平台线程钉住解决方法简介
java·linux·c语言·jvm·c++
All for pursuit.1 小时前
【贪心-4】581.最短无序连续子数组
数据结构·c++·算法·leetcode
weixin_307779131 小时前
从“人操作仪器”到“Agent 自主发现”:OPL 金属材料自驱动实验室 MVP 技术论述
开发语言·人工智能·算法·架构
释厄6231 小时前
01AB 基本元理——任何智能体的三元法理·0=1→0≠1法理跃迁为天理
人工智能·windows·算法·microsoft·机器学习