Erlang 查找最长子字符串的长度
我看到类似的问题,但最终,对于不同的编程语言。我正试图解决这个小问题: 给定一个字符串,查找不带 重复字符。例如,最长的子字符串没有Erlang 查找最长子字符串的长度,erlang,Erlang,我看到类似的问题,但最终,对于不同的编程语言。我正试图解决这个小问题: 给定一个字符串,查找不带 重复字符。例如,最长的子字符串没有 abcabcbb的重复字母为abc,长度为3。对于 bbbbb最长的子字符串是b,长度为1 我不需要答案,但为什么到目前为止我所做的在第二次迭代中失败了 1> longest_substring:main("abcabcbb"). H: 97, T: "bcabcbb", Sub: [] Is 97 in []? false H: 98, T: "cabcb
abcabcbb
的重复字母为abc
,长度为3
。对于
bbbbb
最长的子字符串是b
,长度为1
我不需要答案,但为什么到目前为止我所做的在第二次迭代中失败了
1> longest_substring:main("abcabcbb").
H: 97, T: "bcabcbb", Sub: []
Is 97 in []? false
H: 98, T: "cabcbb", Sub: 97
** exception error: no function clause matching string:chr(97,98,1) (string.erl, line 99)
in function longest_substring:process/2 (src/leetcode/algorithms/longest_substring.erl, line 28)
2>
这是源代码:
-module(longest_substring).
-export([main/1]).
-spec main(S :: string()) -> string().
%%%==================================================================
%%% Export
%%%==================================================================
main(S) -> process(S, "").
%%%==================================================================
%%% Internal
%%%==================================================================
process([], Sub) -> string:len(Sub);
process([H | T], Sub) ->
io:format("H: ~w, T: ~p, Sub: ~p~n", [H, T, Sub]),
Found = string:chr(Sub, H),
io:format("Is ~w in ~p? ~p~n", [H, Sub, Found =/= 0]),
% Don't know how to make this `if` thing better...
if
Found > 0 -> process(T, H);
_ -> process(T, string:concat(Sub, H))
end.
您有两个地方将字符
H
视为字符串,都在if
中:
if
Found > 0 -> process(T, H);
_ -> process(T, string:concat(Sub, H))
end.
这里的H
的两种外观都需要是[H]
,以从单个字符形成字符串。(另外,if
中的最后一个子句需要使用true
,而不是下划线-您应该得到一个编译器错误。)
当前,您的解决方案返回一个数字,而不是字符串。它也无法记住任何可能出现在字符串早期的子字符串。要解决这个问题,您需要记住迄今为止看到的最长的子字符串,这意味着您需要另一个累加器:
-module(longest_substring).
-export([main/1]).
-spec main(S :: string()) -> string().
main(S) -> process(S, {0,[]}, {0,[]}).
process([], {LL,Last}, {LG,_}) when LL > LG -> Last;
process([], _, {_,Long}) -> Long;
process([H | T], {LL,Last}=Sub, {LG,_}=Long) ->
case string:rchr(Last, H) of
0 ->
process(T, {LL+1,string:concat(Last,[H])}, Long);
N ->
NewLast = {1+LL-N,string:substr(Last,N+1)++[H]},
process(T, NewLast,
case LL > LG of
true ->
Sub;
false ->
Long
end)
end.
main/1
功能将两个累加器传递给process/3
,每个累加器都是一对长度和一个列表。第一个累加器跟踪当前的子字符串,第二个累加器跟踪到目前为止看到的最长的子字符串
在process/3
的最后一句中,我们首先检查H
是否在当前子字符串中;如果没有,我们将其添加到当前子字符串中,将其长度增加1,然后使用字符串的尾部再次调用process/3
。但是,如果在当前子字符串中找到H
,我们将使用string:rchr/2
的返回值计算新的当前子字符串,以保留我们可以保留的前一子字符串的最长部分(原始解决方案不这样做)。然后检查当前子字符串的长度是否大于当前最长的子字符串,如果大于,则将其设为最长的子字符串,否则将其丢弃并保留当前最长的子字符串,然后继续使用字符串的尾部。(请注意,我们也可以检查是否大于或等于,而不是大于;这将使我们的函数返回找到的最后一个最长的子字符串,而不是第一个。)
process/3
的前两个子句处理输入字符串已被完全处理的情况。它们只是决定当前子字符串是否比迄今为止看到的最长子字符串长,然后返回两个子字符串中的较长者。(这里也可以使用更大或相等的比较。)您有两个地方将字符H
视为字符串,这两个地方都在if
中:
if
Found > 0 -> process(T, H);
_ -> process(T, string:concat(Sub, H))
end.
这里的H
的两种外观都需要是[H]
,以从单个字符形成字符串。(另外,if
中的最后一个子句需要使用true
,而不是下划线-您应该得到一个编译器错误。)
当前,您的解决方案返回一个数字,而不是字符串。它也无法记住任何可能出现在字符串早期的子字符串。要解决这个问题,您需要记住迄今为止看到的最长的子字符串,这意味着您需要另一个累加器:
-module(longest_substring).
-export([main/1]).
-spec main(S :: string()) -> string().
main(S) -> process(S, {0,[]}, {0,[]}).
process([], {LL,Last}, {LG,_}) when LL > LG -> Last;
process([], _, {_,Long}) -> Long;
process([H | T], {LL,Last}=Sub, {LG,_}=Long) ->
case string:rchr(Last, H) of
0 ->
process(T, {LL+1,string:concat(Last,[H])}, Long);
N ->
NewLast = {1+LL-N,string:substr(Last,N+1)++[H]},
process(T, NewLast,
case LL > LG of
true ->
Sub;
false ->
Long
end)
end.
main/1
功能将两个累加器传递给process/3
,每个累加器都是一对长度和一个列表。第一个累加器跟踪当前的子字符串,第二个累加器跟踪到目前为止看到的最长的子字符串
在process/3
的最后一句中,我们首先检查H
是否在当前子字符串中;如果没有,我们将其添加到当前子字符串中,将其长度增加1,然后使用字符串的尾部再次调用process/3
。但是,如果在当前子字符串中找到H
,我们将使用string:rchr/2
的返回值计算新的当前子字符串,以保留我们可以保留的前一子字符串的最长部分(原始解决方案不这样做)。然后检查当前子字符串的长度是否大于当前最长的子字符串,如果大于,则将其设为最长的子字符串,否则将其丢弃并保留当前最长的子字符串,然后继续使用字符串的尾部。(请注意,我们也可以检查是否大于或等于,而不是大于;这将使我们的函数返回找到的最后一个最长的子字符串,而不是第一个。)
process/3
的前两个子句处理输入字符串已被完全处理的情况。它们只是决定当前子字符串是否比迄今为止看到的最长子字符串长,然后返回两个子字符串中的较长者。(这里也可以使用更大或相等的比较。)为了好玩,我建议您避免复杂的搜索。在这个解决方案中,我为列表中的每个元素创建了一个进程:元素本身、列表中下一个进程/元素的Pid以及调用者的Pid
为了启动搜索,我向每个进程/元素发送一个空列表
每次流程/元素接收到列表时,它都会检查其存储的元素是否是所接收列表的成员。如果是,则将列表发送回调用者,如果不是,则将元素前置到列表,并将新列表发送到下一个进程/元素以继续评估
调用方进程只需等待发送的返回消息的数量
我为列表的最后一个元素添加了一条停止消息和一个特例
-module (longer).
-compile([export_all]).
char_proc(V,Next,Caller) ->
receive
stop -> ok;
Str ->
case lists:member(V,Str) of
true -> Caller ! Str;
false -> send(Next,Caller,[V|Str])
end,
char_proc(V,Next,Caller)
end.
send(noproc,Caller,Str) -> Caller ! Str;
send(Next,_,Str) -> Next ! Str.
find(Str) ->
Me = self(),
Pids = tl(lists:reverse(lists:foldl(fun(X,Acc) -> Pid = spawn(?MODULE,char_proc,[X,hd(Acc),Me]), [Pid|Acc] end,[noproc],Str))),
[X ! [] || X <- Pids],
R = receive_loop(0,[],length(Str)),
[X ! stop || X <- Pids],
R.
receive_loop(N,S,0) -> {N,S};
receive_loop(N,S,I) ->
receive
M when length(M) > N ->
receive_loop(length(M),M,I-1);
_ ->
receive_loop(N,S,I-1)
end.
注意如果存在多个解决方案,则无法保证将返回witch子字符串,修改代码以返回第一个子字符串或