我有两个字符串:
string1 - hello how are you
,
String2 - olo
(包括空格字符)
输出:lo ho
(hel lo ho w是你)
lo ho
是唯一包含string2所有字符的子字符串。
任何人都可以为此建议一个好的算法(我可以认为只有蛮力算法 - O(n ^ 2)。
同样输出应该是最小长度字符串(如果有多个选项)。
答案 0 :(得分:6)
为l
中未出现的字符串2中的字符保留两个指针r
和M = character -> count
以及一个哈希表s[l..r]
。
最初设置l = 0
和r
,以便string1[l..r]
包含string2
的所有字符(如果可能)。你可以通过从M中删除字符直到它为空来完成。
然后在每个步骤中将r
递增1,然后尽可能地增加l
,同时仍保持M为空。所有r - l + 1
的最小值(子串s[l..r]
的长度)都是解决方案。
Pythonish伪代码:
n = len(string1)
M = {} # let's say M is empty if it contains no positive values
for c in string2:
M[c]++
l = 0
r = -1
while r + 1 < n and M not empty:
r++
M[string1[r]]--
if M not empty:
return "no solution"
answer_l, answer_r = l, r
while True:
while M[string1[l]] < 0:
M[string1[l]]++
l++
if r - l + 1 < answer_r - anwer_l + 1:
answer_l, answer_r = l, r
r++
if r == n:
break
M[string1[r]]--
return s[answer_l..answer_r]
如果在执行递增和递减操作时保持正条目数,则可以在O(1)中实现“为空”检查。
让n
为string1
的长度,m
为string2
的长度。
请注意,l
和r
只会递增,因此最多有O(n)个增量,因此最后一个O(n)指令在最后一个外部循环中执行。
如果将M
实现为数组(我假设字母表是常量大小),则会获得运行时
O(n + m),这是最佳的。如果字母表太大,您可以使用哈希表来获得预期的O(n + m)。
执行示例:
string1 = "abbabcdbcb"
string2 = "cbb"
# after first loop
M = { 'a': 0, 'b': 2, 'c': 1, 'd': 0 }
# after second loop
l = 0
r = 5
M = { 'a': -2, 'b': -1, 'c': 0, 'd': 0 }
# increment l as much as possible:
l = 2
r = 5
M = { 'a': -1, 'b': 0, 'c': 0, 'd': 0 }
# increment r by one and then l as much as possible
l = 2
r = 6
M = { 'a': -1, 'b': 0, 'c': 0, 'd': -1 }
# increment r by one and then l as much as possible
l = 4
r = 7
M = { 'a': 0, 'b': 0, 'c': 0, 'd': -1 }
# increment r by one and then l as much as possible
l = 4
r = 8
M = { 'a': 0, 'b': 0, 'c': -1, 'd': -1 }
# increment r by one and then l as much as possible
l = 7
r = 9
M = { 'a': 0, 'b': 0, 'c': 0, 'd': 0 }
最佳解决方案是s [7..9]。
答案 1 :(得分:0)
我会计算string2
中string1
内的字符位置,然后选择最低和最高字符位置之间距离最小的排列:
# positions are:
# 01234567890123456
string1 = 'hello how are you'
string2 = 'olo'
# get string1 positions for each character from set(string2)
positions = {'o': [4, 7, 15],
'l': [2, 3]}
# get all permutations of positions (don't repeat the same element)
# then pick the permutation with minimum distance between min and max position
# (obviously, this part can be optimized, this is just an illustration)
permutations = positions['o'] * positions['l'] * positions['o']
permutations = [[4,2,7], [4,3,7], [4,2,15], ...]
the_permutation = [4,3,7]
# voilà
output = string1_without_spaces[3:7]
答案 2 :(得分:0)
这是使用JavaScript实现的一个示例。逻辑与@Aprillion上面写的类似。
DEMO:http://jsfiddle.net/ZB6vm/4/
var s1 = "hello how are you";
var s2 = "olo";
var left, right;
var min_distance;
var answer = "";
// make permutation recursively
function permutate(ar, arrs, k) {
// check if the end of recursive call
if (k == arrs.length) {
var r = Math.max.apply(Math, ar);
var l = Math.min.apply(Math, ar);
var dist = r - l + 1;
if (dist <= min_distance) {
min_distance = dist;
left = l;
right = r;
}
return;
}
for (var i in arrs[k]) {
var v = arrs[k][i];
if ($.inArray(v, ar) < 0) {
var ar2 = ar.slice();
ar2.push(v);
// recursive call
permutate(ar2, arrs, k + 1);
}
}
}
function solve() {
var ar = []; // 1-demension array to store character position
var arrs = []; // 2-demension array to store character position
for (var i = 0; i < s2.length; i++) {
arrs[i] = [];
var c = s2.charAt(i);
for (var k = 0; k < s1.length; k++) { // loop by s1
if (s1.charAt(k) == c) {
if ($.inArray(k, arrs[i]) < 0) {
arrs[i].push(k); // save position found
}
}
}
}
// call permutate
permutate(ar, arrs, 0);
answer = s1.substring(left, right + 1);
alert(answer);
}
solve();
希望这有帮助。
答案 3 :(得分:0)
有这种算法在O(N)中执行此操作。
想法:有2个阵列,即。 isRequired [256]和isFound [256]告诉S中每个字符的频率,并在解析字符串S时,查找已找到的每个字符的频率。此外,请保留一个计数器,告知何时找到有效窗口。一旦找到有效窗口,我们就可以移动窗口(向右),保持问题的给定不变量。
C ++程序:
void findMinWindow(const char *text, const char *pattern, int &start, int &end){
//Calcuate lengths of text and pattern
int textLen = strlen(text);
int patternLen = strlen(pattern);
// Declare 2 arrays which keep tab of required & found frequency of each char in pattern
int isRequired[256] ; //Assuming the character set is in ASCII
int isFound[256];
int count = 0; //For ascertaining whether a valid window is found
// Keep a tab of minimum window
int minimumWindow = INT_MAX;
//Prepare the isRequired[] array by parsing the pattern
for(int i=0;i<patternLen;i++){
isRequired[pattern[i]]++;
}
//Let's start parsing the text now
// Have 2 pointers: i and j - both starting at 0
int i=0;
int j=0;
//Keep moving j forward, keep i fixed till we get a valid window
for(c=j;c<textLen;c++){
//Check if the character read appears in pattern or not
if(isRequired[text[c]] == 0){
//This character does not appear in the pattern; skip this
continue;
}
//We have this character in the pattern, lets increment isFound for this char
isFound[text[c]]++;
//increment the count if this character satisfies the invariant
if(isFound[text[c]] <= isRequired[text[c]]){
count++;
}
//Did we find a valid window yet?
if(count == patternLen){
//A valid window is found..lets see if we can do better from here on
//better means: increasing i to reduce window length while maintaining invariant
while(isRequired[s[i]] == 0 || isFound[s[i]] > isRequired[s[i]]){
//Either of the above 2 conditions means we should increment i; however we
// must decrease isFound for this char as well.
//Hence do a check again
if(isFound[s[i]] > isRequired[s[i]]){
isFound[s[i]]--;
}
i++;
}
// Note that after the while loop, the invariant is still maintained
// Lets check if we did better
int winLength = j-i+1;
if(winLength < minimumWindow){
//update the references we got
begin = i;
end = j;
//Update new minimum window lenght
minimumWindow = winLength;
}
} //End of if(count == patternLen)
} //End of for loop
}