PS:《剑指offer》是很多同学找工作都会参考的一本面试指南,同时也是一本算法指南(为什么它这么受欢迎,主要应该是其提供了一个循序渐进的优化解法,这点我觉得十分友好)。现在很多互联网的算法面试题基本上可以在这里找到影子,为了以后方便参考与回顾,现将书中例题用Java实现(第二版),欢迎各位同学一起交流进步。
GitHub: https://github.com/Uplpw/SwordOffer。
剑指offer完整题目链接: https://blog.youkuaiyun.com/qq_41866626/article/details/120415258
1 题目描述
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
leetcode链接: 字符串的排列(以下代码已测试,提交通过)
2 测试用例
一般是考虑功能用例,特殊(边缘)用例或者是反例,无效测试用例这三种情况。甚至可以从测试用例寻找一些规律解决问题,同时也可以让我们的程序更加完整鲁棒。
(1)功能用例:字符串不为空,有重复字符以及无重复字符。
(2)边缘用例:字符串只有一个字符。
(3)无效用例:字符串为空。
3 思路
分析:
不管是剑指offer上的解答(字符交换)还是leetcode上的题解(回溯剪枝),总体来说其本质都是固定前面字符,交换后面字符实现全排列(好像学排列组合时也是通过这样的方式求出所有的排列)
为什么会这么讲?看代码实现即明白了,有详细的解释。
最后注意重复字符的处理,利用set记录并判断即可。
4 代码
算法实现1(剑指offer):
import java.util.*;
public class StringPermutation {
public static String[] permutation(String s) {
if (s == null || s.length() == 0)
return null;
List<String> list = new ArrayList<>();
permutationCore(s, list, 0);
return list.toArray(new String[list.size()]);
}
public static void permutationCore(String s, List<String> list, int index) {
// 索引到最后一位字符,交换结束,添加到结果中
if (index == s.length()) {
list.add(s);
}
Set<Character> set = new HashSet<>();
for (int i = index; i < s.length(); i++) {
char[] array = s.toCharArray();
// 集合有相同元素不再添加,并且不再交换,直接跳过,开始下一个字符
if (set.add(array[i])) {
// 当前字符逐渐与后面字符进行交换
swap(array, index, i);
// 当前字符索引往后走一位,由于new创建新的字符串,所以不需要再次交换防止影响后面的结果
permutationCore(new String(array), list, index + 1);
}
}
}
public static void swap(char[] strs, int x, int y) {
char temp = strs[x];
strs[x] = strs[y];
strs[y] = temp;
}
public static void main(String[] args) {
String s = "aabb";
String[] array = permutation(s);
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + "\t");
}
System.out.println();
}
}
算法实现2(leetcode题解):
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class StringPermutation2 {
static List<String> res = new ArrayList<>();
static char[] c;
public static String[] permutation(String s) {
c = s.toCharArray();
permutationCore(0);
return res.toArray(new String[res.size()]);
}
public static void permutationCore(int x) {
// 固定到最后一位字符,将其添加排列方案
if (x == c.length - 1) {
res.add(String.valueOf(c));
return;
}
HashSet<Character> set = new HashSet<>();
for (int i = x; i < c.length; i++) {
// 重复,因此剪枝
if (set.contains(c[i])) {
continue;
}
set.add(c[i]);
// 交换,将 c[i] 固定在第 x 位
swap(i, x);
// 开启固定第 x + 1 位字符
permutationCore(x + 1);
// 恢复交换,防止影响后面的结果
swap(i, x);
}
}
public static void swap(int a, int b) {
char tmp = c[a];
c[a] = c[b];
c[b] = tmp;
}
public static void main(String[] args) {
String s = "aabb";
String[] array = permutation(s);
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + "\t");
}
System.out.println();
}
}
参考
在解决本书例题时,参考了一些大佬的题解,比如leetcode上的官方、K神,以及其他的博客,在之后的每个例题详解后都会给出参考的思路或者代码链接,同学们都可以点进去看看!
本例题参考:
本文如有什么不足或不对的地方,欢迎大家批评指正,最后希望能和大家一起交流进步、拿到心仪的 offer !!!