javascript实现剑指offer——字符串/数组的排列组合题目合集
leetcode:46. 全排列
描述:
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
思路
特殊情况:数组长度==0时,返回[[]];
-
新建一个空数组存放结果
-
全排列的情况考虑递归的方法,
-
首先固定第一个字符,第一个字符可以是数组中的任意元素,所以先遍历数组,拿出第一个元素和剩下的元素;
-
对剩下的元素递归调用,递归的出口是arr长度为1,此时返回[单个元素];
-
最后对递归的结果数组遍历,每一个都拼接上拿出的第一个元素,然后push进结果数组;
注意:长度为1(递归出口)和其他递归情况return格式必须统一为数组,因为如果return一个元素,则无法对return的结果进行数组的遍历,递归到1的时候就会报错:foreach is not a function
代码
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permute = function(nums) {
let result = [];
// 长度为1,直接返回自身
if (nums.length <= 1) {
return [nums];
}
for (let i = 0; i < nums.length; i++) {
//遍历每一个数组元素,
let first = nums[i]; //作为排列数组的第一个
let newArr = nums.slice(0, i).concat(nums.slice(i + 1)); //剔除愿数组中的“first”,保存起来
let others = permute(newArr); //对newArr递归调用,返回剩下的数组元素的全排列数组
// 遍历others数组,对每个排列拼接first
others.forEach(item => {
result.push([].concat(first, item));
});
}
return result;
};
permute([1, 2, 3]);
leetcode:47. 全排列 II
描述:
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
思路
- 其他同上,关键是数组元素重复,导致全排列得到的结果会有重复,所以在最后这里加上一层数组去重。
- 这里是二维数组,二维数组去重比较特殊,不能使用set(Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。),实验结果set只能去掉第一个重复的数组(???)
- 通过对象的键值对来实现二维数组去重,首先新建一个空对象,作为对照;
- 然后遍历数组,对每个元素判断对象里面是否有对应的key,有的话,就代表这个元素被遍历到过,从原来数组里删掉这个重复的元素,然后i–(否则会漏过下一个元素)
- 没有的话,把这个obj【key】=1,作为对照。
- 出口:遍历完成,原数组重复元素被删除。
var permuteUnique = function(nums) {
function permute(nums) {
let result = [];
// 长度为1,直接返回自身
if (nums.length <= 1) {
return [nums];
}
for (let i = 0; i < nums.length; i++) {
//遍历每一个数组元素,
let first = nums[i]; //作为排列数组的第一个
let newArr = nums.slice(0, i).concat(nums.slice(i + 1)); //剔除愿数组中的“first”,保存起来
let others = permute(newArr); //对newArr递归调用,返回剩下的数组元素的全排列数组
// 遍历others数组,对每个排列拼接first
others.forEach(item => {
result.push([].concat(first, item));
});
}
return result;
}
let result2 = permute(nums);
let obj = {};//对照对象
for (var i = 0; i < result2.length; i++) {
// 判断当前项是否遍历过,是则删除,否存入obj以作对照
if (obj[result2[i]]) {
result2.splice(i, 1);
i--; //数组删除了一项,要把i回退一下,不然会跳过下一项不去遍历
} else {
obj[result2[i]] = 1;
}
}
// return arr;
return result2;
};
var result = permuteUnique([1, 1, 2]);
牛客网:字符串的排列
描述
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
思路
字符串的排列和上面思路基本类似,不同点:
- 特殊情况:字符串为“”时输出为[],多加一层判断
- 字符串的连接用“+”
- 对于有重复字符的字符串,最后对result数组去重,就可以剔除掉全排列重复的部分了
数组去重方法具体请看我的另一篇博文https://blog.****.net/weixin_28900307/article/details/88384480
代码
function Permutation(str) {
let result = [];
// 长度为1,直接返回自身
if (str.length <= 1) {
return str.length == 0 ? [] : [str]; //单个字符串也要放进数组里,这样递归调用的返回才能统一:全是数组
}
for (let i = 0; i < str.length; i++) {
//遍历每一个数组元素,
let first = str[i]; //作为排列数组的第一个
let newArr = str.slice(0, i) + str.slice(i + 1); //剔除愿数组中的“first”,保存起来
let others = Permutation(newArr); //对newArr递归调用,返回剩下的数组元素的全排列数组
// 遍历others数组,对每个排列拼接first
others &&
others.forEach(item => {
result.push(first + item);
});
}
result = [...new Set(result)];
return result;
}
Permutation("abc");