找到最长子串的长度

时间:2016-03-30 18:11:11

标签: erlang

我看到类似这样的问题,但最终,对于不同的编程语言。我正在努力解决这个小问题:

  

给定一个字符串,找到没有的最长子字符串的长度   重复的人物。例如,最长的子串没有   重复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.

2 个答案:

答案 0 :(得分:1)

您有两个地方将字符 In [302]: cutoff_ar Out[302]: array([ 1, 3, 9, 44, 63, 90]) In [303]: pan_series_arr Out[303]: array([ 2, 8, 69, 55, 97]) In [304]: [(pan_series_arr < cutoff_val).sum() for cutoff_val in cutoff_ar] Out[304]: [0, 1, 2, 2, 3, 4] In [305]: sortidx = pan_series_arr.argsort() ...: out = np.searchsorted(pan_series_arr,cutoff_ar,'right',sorter=sortidx) ...: In [306]: out Out[306]: array([0, 1, 2, 2, 3, 4]) 视为字符串,均位于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是否在当前子字符串中;如果没有,我们将它添加到当前子字符串,将其长度增加1,并再次使用字符串的尾部调用H。但是如果在当前子字符串中找到process/3,我们使用H的返回值来计算新的当前子字符串,以保留我们可以使用的前一个子字符串的最长部分(原始解决方案不执行此操作) )。然后我们检查当前子字符串的长度是否大于当前最长的子字符串,如果是,我们将其设为最长的子字符串,或者如果不是,我们将其丢弃并保留当前最长的子字符串,然后继续弦的尾巴。 (注意,我们也可以使这个检查更大或更大而不是更大;这将使我们的函数返回我们找到的最后一个最长的子字符串而不是第一个。)

string:rchr/2的前两个子句处理输入字符串已完全处理的情况。他们只是决定当前的子串是否长于目前为止看到的最长子串并返回两者中的较长者。 (使用更大或相等比较的替代方案也适用于此。)

答案 1 :(得分:1)

为了好玩,我建议你避免复杂的搜索。在这个解决方案中,我为列表保存的每个元素创建一个进程:元素本身,列表中下一个进程/元素的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.

在shell中测试:

1> c(longer).
{ok,longer}
2> longer:find("abcdad").
{4,"abcd"}
3> longer:find("abcdadtfrseqgepz").
{9,"adtfrseqg"}
4> longer:find("aaaaaaaaaaaa").    
{1,"a"}
5> longer:find("abcdatfrseqgepz"). 
{11,"bcdatfrseqg"}
6>

注意如果存在多个解决方案,则无法保证将返回女性子字符串,很容易修改代码以返回第一个子字符串或所有子字符串。