以下是面试问题。我没有做到这一点,因为我没有预料到的更好,更有效的答案,我没有。
给定一个字符串S,我们需要找到模式XYYX的回文数,其中X和Y是同一个字符串S中的任何字符。
注意:我们不能改变字符串S中字符的顺序.X和Y的值也可以相同,但它们在字符串S中的位置需要不同。
此外,如果字符串S中的索引对于最终字符串
中的任何字符不同,则两个字符串不同示例:Say string是S = abbaab,然后是4。
四个这样的回文是:
//In Java.
exposeObject(myObject, "nameOfMyObject");
--Then in Lua
nameOfMyObject:myFunction();
那么如何计算这些回文的数量。字符串的长度可以达到1000000.那么最好的方法是什么呢?
答案 0 :(得分:0)
如问题的讨论部分所示,目标不是找到真实的"回文但像是" XYYX *"每个" X *"匹配计算。
这意味着您需要在迭代输入S
时保持一些搜索状态,就像S
的每个位置一样,可能有多个回文。
现在考虑" abbaaaa的(最坏情况?)输入...." (以" abba&#34开头;以(1000000 - 4)
' a' -characters结尾。在这种情况下,我们需要维护多少个状态实例?答案取决于如何定义了状态机(维护状态)。
提到的状态机是比赛的检测器。让我们看一些代码(选择F#):
type PState =
| X of char
| Y0 of char * char
| Y1 of char * char
| X1 of char * char
| XN of char * char
| End
let tryProgress c = function
| X(x) -> Some(Y0(x,c))
| Y0(x,y) -> if c = y then Some(Y1(x,y)) else None
| Y1(x,y) -> if c = x then Some(X1(x,y)) else None
| X1(x,y) -> if c = x then Some(XN(x,y)) else Some (End)
| XN(x,y) -> if c = x then Some(XN(x,y)) else Some (End)
| End -> failwith "This instance is done and should have been dismissed."
let count (s : string) =
s.ToCharArray()
|> Array.fold (fun (states,counter) c ->
let counter1 = ref 0
(X(c)) :: (states
|> List.map (fun fsm ->
let res = tryProgress c fsm
// printfn "%A -> %c -> %A" fsm c res
match res with
| None -> None
| Some(X1(x,y)) ->
counter1 := !counter1 + 1
Some(X1(x,y))
| Some(XN(x,y)) ->
counter1 := !counter1 + 1
Some(XN(x,y))
| Some(End) ->
counter1 := !counter1 + 1
None
| Some(fsm1) -> Some(fsm1)
)
|> List.filter (fun mfsm -> match mfsm with | Some(fsm) -> true | None -> false)
|> List.map (fun mfsm -> Option.get mfsm))
, (!counter1 + counter)
) ([],0)
|> snd
let s = "abbaab"
count s
(*
Yields:
val it : int = 4
as hoped for.
*)
类型PState
是一个有区别的联合,它描述了状态机的各个状态以及各个状态所需的数据。
tryProgress
函数从S获取fsm的实例和下一个输入字符并返回Pstate option
结果。如果字符没有导致新的可能状态,则此函数返回None
,否则返回Some <resulting state>
。
最后,count
函数迭代输入字符串中的字符(也可以按字母顺序读取输入文件...)并将tryProgress
函数应用于每个活动状态机。它也决定了哪些情况会忘记&#34;并维持和决定何时增加发现的伪回文的计数器。
回到我们所谓的最坏情况输入场景,保留的FSM实例数将随着字符数的增加而增加,X = Y也无助于减少要保留的状态数。大多数这些实例将处于状态XN('a','a')
,直到序列结束。
因此,我很想把这个问题归为一个不合适的问题。
("aaaaaaa" -> [0,1,2,3;0,1,2,4;0,1,2,5;0,1,2,6; 1,2,3,4; 1,2,3,5; 1,2,3,6; ...]
)。
<强>更新强>
由于代码示例需要另一种语言,这里是流行的C ++版本:
#include <cstdint>
#include <string>
#include <list>
#include <iostream>
#include <exception>
#include <stdexcept>
enum class PStateName
{
X,Y0,Y1,X1,XN,END,FAIL
};
struct PState
{
PStateName state;
char x;
char y;
PState(PStateName s, char x0, char y0 = '\0')
: state(s)
, x(x0)
, y(y0)
{
}
static PState MakeX(char x0)
{
return PState(PStateName::X, x0);
}
static PState To_Y0(const PState &pre, char y0)
{
return PState(PStateName::Y0,pre.x, y0);
}
static PState To_Y1(const PState&pre)
{
return PState(PStateName::Y1,pre.x,pre.y);
}
static PState To_X1(const PState&pre)
{
return PState(PStateName::X1,pre.x,pre.y);
}
static PState To_XN(const PState&pre)
{
return PState(PStateName::XN,pre.x,pre.y);
}
static PState To_End(const PState&pre)
{
return PState(PStateName::END,pre.x,pre.y);
}
static PState To_Fail(const PState&pre)
{
return PState(PStateName::FAIL,pre.x,pre.y);
}
};
PState Progress(const PState& current, char c)
{
switch(current.state)
{
case PStateName::X:
return PState::To_Y0(current,c);
break;
case PStateName::Y0:
if(c == current.y)
return PState::To_Y1(current);
else
return PState::To_Fail(current);
break;
case PStateName::Y1:
if(c == current.x)
return PState::To_X1(current);
else
return PState::To_Fail(current);
break;
case PStateName::X1:
if(c == current.x)
return PState::To_XN(current);
else
return PState::To_End(current);
break;
case PStateName::XN:
if(c == current.x)
return PState::To_XN(current);
else
return PState::To_End(current);
break;
case PStateName::END:
throw std::exception(/*"Instances in state End should have been dismissed and never show here."*/);
break;
case PStateName::FAIL:
throw std::exception(/*"Instances in state FAIL should have been dismissed and never show here."*/);
break;
default:
throw std::exception(/*"Fix me! Unknown state in a switch statement!"*/);
break;
}
}
typedef std::list<PState> StateList;
StateList nextChar( const StateList& actives, char c, size_t &counter )
{
StateList result;
for(auto fsm : actives)
{
PState fsm1 = Progress(fsm,c);
switch(fsm1.state)
{
case PStateName::FAIL: // Do nothing - weed out and do not count it.
break;
case PStateName::X1:
counter++;
result.push_back(fsm1);
break;
case PStateName::XN:
counter++;
result.push_back(fsm1);
break;
case PStateName::END:
counter++;
break;
default:
result.push_back(fsm1);
break;
}
}
result.push_back(PState::MakeX(c));
return result;
}
size_t countString( const std::string& s)
{
size_t counter = 0;
StateList current;
for(auto c : s)
{
current = nextChar(current,c,counter);
}
return counter;
}
size_t countFile( const std::string& filePath)
{
size_t counter = 0;
StateList current;
// TODO: read file char by char and feed it to nextChar as shown in the countString() function.
return counter;
}
int main(int argc, const char * argv[])
{
std::string s("abbaab");
std::cout <<"\"" << s << "\": " << countString(s) << std::endl;
return 0;
}