【问题标题】:Solving "first unique character in a string" in Elixir [closed]在 Elixir 中解决“字符串中的第一个唯一字符”[关闭]
【发布时间】:2021-03-21 07:09:42
【问题描述】:

我正在尝试在 Elixir 中解决 LeetCode 问题,因为没有大量资源可用于该语言的代码审查(尽管这可能会改变或者我可能错了)而且因为我来自 OOP 背景,所以我想我会继续在这里发帖。

我正在尝试使用 Elixir 解决 "first unique character in a string" LeetCode 问题,发现我的解决方案比我想象的要复杂,因为我不知道 Elixir 中的 Maps 的键自动按字母顺序排序,而不是按插入(虽然我可能是错的)。

我很想听听任何更简洁/更容易解决问题的解决方案。 FWIW,我打算把它们写在最后,以便其他人能够找到如何解决我自己找不到的问题的示例。

Given a string, find the first non-repeating character in it and return its index. If it doesn't exist, return -1.

Examples:

s = "leetcode"
return 0.

s = "loveleetcode"
return 2.
 

Note: You may assume the string contains only lowercase English letters.
defmodule Algos do
  def first_unique_char_index(str) do
    
    arr = String.split(str, "", trim: true)
    indexes = Enum.with_index(arr)

    first = Enum.frequencies(arr)
    |> Map.to_list
    |> Enum.sort(fn ({a,_b}, {c,_d}) -> 
      {_char1, i1} = Enum.find(indexes, (fn {x,_i} -> x == a end)) 
      {_char2, i2} = Enum.find(indexes, (fn {y,_j} -> y == c end))
      i1 <= i2 
      end)
    |> Enum.find(fn {_char, num} -> num == 1 end)

    case first do
      {char, _num} ->
        result = Enum.find(indexes, fn {x, _i} -> char == x end)
        {_letter, index} = result
        index
      nil ->
        -1
    end

  end

end

Algos.first_unique_char_index("aabcc") # returns 2
Algos.first_unique_char_index("picadillo") # returns 0
Algos.first_unique_char_index("dood") # returns -1 

【问题讨论】:

  • 旁注: elixir中的Maps不以任何方式排序。
  • 我投票结束这个问题,因为这个问题属于codereview.stackexchange.com
  • @PawełObrok 虽然这可能是 CR 的主题,但在未来,请不要以 Code Review 站点的存在作为关闭问题的理由。评估请求并使用诸如需要更多关注(就像我在这里所做的那样)、主要基于意见等原因。然后您可以向 OP 提及它可以如果是 on-topic,请在 Code Review 上发布。请看Does being on-topic at another Stack Exchange site automatically make a question off-topic for Stack Overflow?
  • @SᴀᴍOnᴇᴌᴀ 将其标记为审核并请求转移到 codereview 是否有意义?
  • @PawelObrok 谢谢你的提问。请参阅this meta question 的答案。通常情况下,如果这里已经没有答案,我会说是,但该元数据的两个答案都指出“如果有答案,它们也都需要在代码审查中成为很好的答案。”坦率地说我不认为这里接受的答案是 CR 的好答案。

标签: algorithm functional-programming elixir


【解决方案1】:

这是一个很好的小谜题,可以通过几个累加器来解决。您可以使用内部二进制表示,而不是拆分字符串,或者(为了跳过编码所涉及的额外复杂性)您可以将字符串转换为字符列表并专注于整数组件。

这是一个可能的解决方案(未经彻底测试):

defmodule FirstUniq do
  def char(string) do
    [first_char | rest] = to_charlist(string)
    eval_char(first_char, 0, rest, rest)
  end

  # Case where we hit the end of the string without a duplicate!
  defp eval_char(_char, index, [], _), do: index

  # Case where a character repeats... increment the index and eval next char
  defp eval_char(char, index, [x | _], [next_char | rest]) when char == x do
    eval_char(next_char, index + 1, rest, rest)
  end

  # Case where the character does not repeat: keep looking
  defp eval_char(char, index, [x | rest], acc2) when char != x do
    eval_char(char, index, rest, acc2)
  end
end

# should be 0 (because "l" does not occur more than once)
IO.puts(FirstUniq.char("leetcode"))

# should be 2 (because "v" is the first char that does not repeat)
IO.puts(FirstUniq.char("loveleetcode"))

这项艰巨的工作由eval_char/4 函数完成,其多个子句的作用类似于case 语句。诀窍是我们必须保留两个累加器,这类似于嵌套循环。

我会推荐 Exercism's Elixir Track 来展示您在该语言中会遇到的许多常见模式。

【讨论】:

    【解决方案2】:

    以下可能是最高效的解决方案;我决定把它放在这里,因为它揭示了几个有趣的技巧。

    "leetcode"
    |> to_charlist()
    |> Enum.with_index() # we need index to compare by
    |> Enum.reduce(%{}, fn {e, i}, acc ->
      # trick for the future: `:many > idx` for any integer `idx` :)
      Map.update(acc, e, {e, i}, &{elem(&1, 0), :many})
    end)
    |> Enum.sort_by(&elem(elem(&1, 1), 1)) # sort to get a head
    |> case do
      [{_, {_, :many}} | _] -> "All dups"
      [{_, {result, index}} | _] -> {<<result>>, index}
      _ -> "Empty input"
    end
    #⇒ {"l", 0}
    

    【讨论】:

    猜你喜欢
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 1970-01-01
    • 1970-01-01
    • 2020-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多