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

文章摘要:

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

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

相关推荐
四斤年华2 小时前
关于SpringBoot在MultipartFile上java.nio.file.NoSuchFileException: /tmp/undertow
java·spring boot·nio
宵时待雨2 小时前
优选算法专题2:滑动窗口
数据结构·c++·笔记·算法
Mr_pyx2 小时前
LeetCode HOT 100 —— 矩阵置零(多种解法详解)
算法·leetcode·矩阵
葫三生2 小时前
《论三生原理》系列:文化自信、知识范式重构与科技自主创新的思想运动源头?
大数据·人工智能·科技·深度学习·算法·重构·transformer
杰克尼2 小时前
天机学堂项目总结(day3~day4)
java·开发语言·spring
Q741_1472 小时前
每日一题 力扣 3761. 镜像对之间最小绝对距离 哈希表 数组 C++ 题解
c++·算法·leetcode·哈希算法·散列表
John.Lewis2 小时前
C++加餐课-哈希:扩展学习(2)布隆过滤器
c++·算法·哈希算法
摇滚侠2 小时前
给我提供一个 sqlyog 下载地址
java
Seven972 小时前
【从0到1构建一个ClaudeAgent】协作-团队协议
java