【LeetCode & 剑指offer刷题】字符串题9:38 字符串的排列(全排列问题)
【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)
38 字符串的排列(全排列问题)
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(
可能有字符重复)
,字符只包括大小写字母。
/*
问题:全排列(含重复元素,且要求按字典序输出)
方法一:交换法,递归
用哈希表记录,以解决存在重复元素的全排列问题
参考问题总结“排列与组合”
*/
class
Solution
{
public
:
vector
<
string
>
Permutation
(
string str
)
{
vector
<
string
>
result
;
if
(
str
.
empty
())
return
result
;
per
(
str
,
0
,
result
);
sort
(
result
.
begin
(),
result
.
end
());
//排序,以便之后产生字典序的全排列(这里是产生序列之后再排序,通过改进算法可以实现按字典序push)
return
result
;
}
private
:
void
per
(
string
&
str
,
int
begin
,
vector
<
string
>&
result
)
{
if
(
begin
>=
str
.
size
()-
1
)
{
result
.
push_back
(
str
);
return
;
}
else
{
unordered_set
<
char
>
record
;
//记录出现过的字符
for
(
int
i
=
begin
;
i
<
str
.
size
();
i
++)
//产生排列的多个分支
{
if
(
record
.
find
(
str
[
i
])
==
record
.
end
())
//只和没交换过的交换
{
record
.
insert
(
str
[
i
]);
swap
(
str
[
begin
],
str
[
i
]);
//与后面元素交换,以产生不同字符开头的排列
per
(
str
,
begin
+
1
,
result
);
//递归产生分支的深度
swap
(
str
[
begin
],
str
[
i
]);
//归位,以便下次交换
}
}
}
}
};
/*
方法二:
dfs(掌握)
用
map
记录,以解决存在重复元素的全排列问题
*/
class
Solution
{
public
:
vector
<
string
>
Permutation
(
string str
)
{
vector
<
string
>
result
;
if
(
str
.
empty
())
return
result
;
string path
;
map
<
char
,
int
>
counter
;
//
用
map
时,
key
值存储为有序的,最后输出的排列也是有序的
// sort(str.begin(), str.end()); //
上面用了
map,
故这里无需先
sort
了
for
(
char
a
:
str
)
counter
[
a
]++;
//
统计
str
中各数出现的次数,没有
key
的时候会自动创建
dfs
(
str
,
result
,
path
,
counter
);
//
递归
return
result
;
}
private
:
void
dfs
(
string
&
str
,
vector
<
string
>&
result
,
string
&
path
,
map
<
char
,
int
>&
counter
)
{
if
(
path
.
size
() == str.size())
//
到达树的末尾,将单路径数组
push
到结果向量中
{
result
.
push_back
(
path
);
return
;
}
for
(
auto
&
p
:
counter
)
//for
循环带来的是树宽度方向的延伸,即产生同一层的多个分支
{
if
(
p
.
second
>
0
)
//
如果该元素没有被取完(某个元素可能会出现多次)
{
path
.
push_back
(
p
.
first
);
p
.
second
--;
//
已经取了这个元素,统计数减一
dfs
(
str
,
result
,
path
,
counter
);
//
继续往深度方向延伸
path
.
pop_back
();
//
回溯,给其他分支腾空间!!
p
.
second
++;
}
}
}
};
567
.
Permutation in String
Given two strings
s1
and
s2
, write a function to return true if
s2
contains the permutation of
s1
. In other words, one of the first string's permutations is the
substring
of the second string.
Example 1:
Input:
s1 = "ab" s2 = "eidbaooo"
Output:
True
Explanation:
s2 contains one permutation of s1 ("ba").
Example 2:
Input:
s1= "ab" s2 = "eidboaoo"
Output:
False
Note:
-
The input strings only contain lower case letters.
-
The length of both given strings is in range [1, 10,000].
/*
问题:判断s1的全排列中是否有排列是s2的子串
统计表+滑动窗口
统计s1各字符出现的次数,并用s1长度的滑动窗框住s2,统计各滑动窗各字符出现的次数,如果与s1中相等,则返回true
*/
class
Solution
{
public
:
bool
checkInclusion
(
string s1
,
string s2
)
{
if
(
s1
.
empty
()
||
s2
.
empty
())
return
false
;
int
n1
=
s1
.
size
(),
n2
=
s2
.
size
();
vector
<
int
>
m1
(
128
),
m2
(
128
);
//统计表(也可用hash表)
for
(
int
i
=
0
;
i
<
n1
;
++
i
)
//对s1,s2中前n1个字符统计
{
m1
[
s1
[
i
]]++;
m2
[
s2
[
i
]]++;
}
if
(
m1
==
m2
)
return
true
;
//若各字符出现的次数相等,说明可以由s1排列得到当前s2中的子串
for
(
int
i
=
n1
;
i
<
n2
;
++
i
)
//滑动窗口扫描s2
{
m2
[
s2
[
i
]]++;
m2
[
s2
[
i
-
n1
]]--;
if
(
m1
==
m2
)
return
true
;
}
return
false
;
}
};
posted @
2019-01-05 15:56 wikiwen 阅读(
...) 评论(
...) 编辑 收藏