【问题标题】:Simple solution for Isomorphic string check which just coulnd't pass 1 test case无法通过 1 个测试用例的同构字符串检查的简单解决方案
【发布时间】:2016-05-21 14:36:20
【问题描述】:

以下是我对leetcode中给出的同构字符串问题的解决方案:

public bool IsIsomorphic(string s, string t)
    {
        int[] s1 = new int[s.Length];
        int[] t1 = new int[t.Length];
        bool isI = true;
        if (s1.Length > 0 && t1.Length > 0)
        {
            s1[0] = 0;
            int i = 1;
            int j = 1;
            for (i = 1; i < s.Length; i++)
            {
                if (s[i] == s[i - 1])
                {
                    s1[i] = 1;
                }
                else
                {
                    s1[i] = 0;
                }
            }
            for (j = 1; j < t.Length; j++)
            {
                if (t[j] == t[j - 1])
                {
                    t1[j] = 1;
                }
                else
                {
                    t1[j] = 0;
                }
            }
            for (int k = 0; k < s1.Length; k++)
            {
                if(s1[k] != t1[k])
                {
                    isI = false;
                }
            }
        }
        else
        {
            isI = true;
        }
        return isI;
    }

它通过了 29/30 个测试用例,但没有通过以下长得离谱的测试用例。与谷歌驱动器中的输入共享代码:

https://docs.google.com/document/d/1UkG8Rc6VItiihwvqzJdM3uMHIX-BCsslJ_lVklkxvq8/edit?usp=sharing

任何帮助都会很棒。

【问题讨论】:

  • 由于这是某种锻炼/测验网站,我想知道:您需要什么样的帮助:只需指出代码中的错误或正确的解决方案?
  • 代码没有错误。我需要知道的是为什么只有 1 个测试用例会返回错误的输出,是因为什么?
  • “代码中没有错误”看起来与“仅 1 个测试用例返回错误输出”有点不一致,你不是说吗?
  • @AakashM 没有错误我的意思是没有编译器或运行时错误,很惊讶你没有这样考虑,为什么还要指出这样无用的东西?

标签: c# string algorithm string-matching string-algorithm


【解决方案1】:

好的,因为你没有说明你的算法是如何工作的,让我们来做所有繁重的工作,然后我自己去理解它,检查它并提出另一个更愉快的替代方案。

假设您可能这样做会导致您出错。

您编写算法 + 猜测您尝试过的内容。

您在每个字符串上进行迭代,并且仅检查是否重复出现在同一索引中但在相反的两侧,如果它们是您正在标记它们,则为 1,否则为 0。其他字符串也是如此。当您完成对两个字符串的迭代时,您正在检查这些值是否相等。

这是一个错误的假设。

错误假设 #1:仅放置在 2 个字符上
仅放置在两个数字 0、1 上来表示字符串上的重复是不可能的,因此是不正确的。
当我们有几个重复字符时会发生什么?假设在当前算法中 Banana,你不能只用 2 个字符来表示 Ban .
洞察:现在我们明白,对于每个唯一字符,我们都需要新的数字。

错误假设 #2:标记重复字符
让我们假设为每个字符分配一个数字。

  1. 我们如何识别新角色?这意味着我们需要扫描旧字符以查看它是否已经存在,这意味着我们不能对字符串进行一次快速扫描,这意味着我们需要扫描每个当前的 I(index) 字符以查找 0-(I -1) 看看那个词是否已经存在。这导致我们遇到另一个问题,我们有数字而不是实际字符?我们现在在干什么 ?创建另一个数组来保存字符的每个唯一数字?这意味着另一个数组(复杂性和内存)。

  2. 假设我们有 6 个长字符串,您只想通过比较索引值来扫描重复字符 0,5 | 1,4 | 2, 3 这不足以确定它们是重复的,因为您正在假设您知道一个字符串中的重复字符应该是什么顺序(索引),这是我们无法预见的。例如:banana => b != a, a != n, n != a 这意味着这个词没有重复字符?这显然是错误的。

正如你所看到的,我们可以闻到一些有趣的事情正在发生,这么小的一部分很麻烦。

如果我们能投入更多时间在如何以更有效的方式解决这个问题,以及我们拥有的可供处置的工具上(我们可以通过我们的self [Array over Dictionary]) 我们会发现所有这些问题。

永远投资于设计,值得投资,你不会后悔的。

解决方案 #1:
为什么使用数字?让我们使用实际的字符。 在这种情况下,另一种解决方案是更好的选择。

public bool IsIsomorphic(string s, string t)
{
    if (s.Length != t.Length)
    {
        return false;
    }

    bool result = true;
    var relation = new Dictionary<char, char>();
    for (int i = 0; i < s.Length; i++)
    {
        char sChar = s[i];
        char tChar = t[i];
        char c;
        if (relation.TryGetValue(sChar, out c))
        {
            if (c != tChar)
            {
                result = false;
                break;
            }
        }
        else if (relation.ContainsValue(tChar))
        {
            result = false;
            break;
        }
        else
        {
            relation.Add(sChar, tChar);
        }
    }
    return result;
}

解决方案 #2:
更多的内存,更少的可读性,无需使用外部工具(最后的检查是简单的数组值比较)

public bool IsIsomorphic3(string s, string t)
{
    if (s.Length != t.Length)
    {
        return false;
    }

    int[] firstNumbering = new int[26];
    int[] firstStringOrder = new int[s.Length];
    int firstCounter = 0;
    for (int i = 0; i < s.Length; i++)
    {
        char c = s[i];
        if (firstNumbering[c - 'a'] == 0)
        {
            firstNumbering[c - 'a'] = ++firstCounter;
        }
        firstStringOrder[i] = firstNumbering[c - 'a'];
    }

    int[] secondNumbering = new int[26];
    int[] secondStringOrder = new int[t.Length];
    int secondCounter = 0;
    for (int j = 0; j < t.Length; j++)
    {
        char c = t[j];
        if (secondNumbering[c - 'a'] == 0)
        {
            secondNumbering[c - 'a'] = ++secondCounter;
        }
        secondStringOrder[j] = secondNumbering[c - 'a'];
    }

    return firstStringOrder.SequenceEqual(secondStringOrder); // Comparing values using Linq
}

【讨论】:

  • 第一:我支持该解决方案。它更干净,更短,更易读,也更正确。第二:为你在这篇文章中所做的工作点赞:-D
  • 我在另一个解决方案中看不到重点,我可以使用字典类型的数据结构,但我想以一种非常简单的方式来做。我的在 log(n) 中运行,你的也是。至于重复的单词,我看不出我的解决方案有什么问题,例如“paper”、“title”会返回 true 或“banana”,“apples”总是会返回 false,因为数组将是:[0,0, 0,0,0,0] 和 [0,0,1,0,0,0] 根据我的解决方案。如果可能的话,在 leetcode 中用不同的输入运行我的代码,你就会明白了。
  • 正如我所解释的,在您的算法逻辑中,您正在“检查” s[i] 和 s[i-1] 以确定它们是否在重复,重复不必紧挨着彼此,“pabcpde”将是“0000000”,这本身当然是不正确的,甚至没有检查其他字符串涉及。顺便说一句,我们的解决方案(你的和我的#1)都不是 log(n) 异常解决方案#2,它是 O(3n) => O(n)。
  • @user3036757,添加了另一个“简单”解决方案。
  • 新解决方案不起作用,因为文本包含标点符号等。 @ user3036757:您的解决方案不会注意到“aabbaabb”和“aabbaacc”不是同构的。您也没有指定您想要什么样的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多