在c ++中查找不适用于特定测试用例的最长子字符串

时间:2018-06-07 04:05:41

标签: c++ string hashtable

Q)没有重复字符的最长子字符串

鉴于" abcabcbb",答案是" abc",长度为3。

鉴于" bbbbb",答案为" b",长度为1。

鉴于" pwwkew",答案为" wke",长度为3.注意答案必须是子字符串," pwke"是一个子序列而不是子串。

我的回答:

class Solution {
public:
int lengthOfLongestSubstring(string s) {
    int count[256];
    int dummy=0;
    int c=0;
    for(int i=0;i<256;i++){
        count[i]=0;
    }
    for(int i=0;i<s.length();i++){
        count[s[i]]++;
        if(count[s[i]]==1){
        c++;
        i++;
        //cout<<c;
        }
        else{
        //cout<<C;
        dummy=dummy>c?dummy:c;
        //cout<<dummy;
        c=0;
            for(int j=0;j<256;j++){
                count[j]=0;
            }
            i++;
        }

    }
     return dummy;
}
};

我知道这不是最佳解决方案,但我是新手。这段代码适用于很多测试用例,除了字符串&#34; pwwkew&#34;原来答案是3,但我得到0。

我尝试过:

对于字符串"abcabcbb",我得到正确的输出,即3。

对于字符串"bbbb",我得到正确的输出,即1。

对于特定字符串"pwwkew",我将其设为0.在这种情况下答案应为3。

我尝试打印这些值以检查出错的地方。对于第三种情况,它似乎没有输入else语句。 if语句中的cout打印123。但它应该为12打印pw。 else语句中的cout不起作用。

为什么只有这种情况我输错了?

请帮助我。

1 个答案:

答案 0 :(得分:1)

我认为OP的算法存在错误(或至少缺失)。

我完全不了解算法,但至少要计算出字符的出现次数。如果特定字符的count不是1,则会找到重复项,并且count数组已完全重置。恕我直言,这是错误的观点。 count数组退化为标志数组(这还不够)。

反例pwwkwe

  • s[2]
  • 重复
  • 重置count(即重启)
  • s[4]
  • 重复
  • 重置count(即重启)。

因此,检测到的最长子字符串的长度最多为2.但从k开始实际上是3(kwe)。

所以,我提出了一个不同的想法:

一旦发现副本,最长的子字符串实际上可能会在此字符的上一次出现之后开始。考虑到这一点,副本不再是重复。

这听起来有点令人困惑。可能是,当我展示我是如何解决它时,它变得更容易理解:

count不再用作标志数组。相反,最后一次出现的索引存储在那里(对于每个字符)。因此,对于每个字符,可以检查到其先前出现的距离(该字符没有重复)。但是,它必须没有任何重复。因此,我还引入了一个起始索引(i0),它始终在前一个字符出现后设置一次。 (不考虑开始索引之前的重复。)这样,在确定正确的子字符串时,只考虑最后一个副本。

在代码中:

#include <iostream>
#include <string>

/* determines longest substring without duplicated characters.
 * param s ... string to evaluate
 * return: pair of
 *   first  ... start index of found substring
 *   second ... length of found substring
 */
std::pair<int, int> lengthOfLongestSubstring(const std::string &s)
{
  // index of last occurrence for each character
  // (-1 ... character not yet occurred)
  int iChrLast[256];
  for (int &i : iChrLast) i = -1;
  // result start index, length
  std::pair<int, int> result(0, 0);
  // check all characters (i0 ... current start)
  for (int i = 0, i0 = 0; i < (int)s.length(); ++i) {
    // cast char to index (via (unsigned char) to prevent negative indices)
    const int c = (unsigned char)s[i];
    // check if there is a duplicate after current start
    if (iChrLast[c] >= i0) i0 = iChrLast[c] + 1;
    // compute length with current start
    const int len = i - i0 + 1;
    // check whether new max. length found (update in case)
    if (result.second < len) result = std::make_pair(i0, len);
    // remember last occurrence of this char
    iChrLast[c] = i;
  }
  // done
  return result;
}

int main()
{
  const std::string tests[] = {
    "abcabcbb",
    "bbbbb",
    "pwwkew"
  };
  for (const std::string &test : tests) {
    const std::pair<int, int> result = lengthOfLongestSubstring(test);
    std::cout << test << ": " << result.first << ", " << result.second
      << " ("<< test.substr(result.first, result.second) << ")\n";
  }
  return 0;
}

输出:

abcabcbb: 0, 3 (abc)
bbbbb: 0, 1 (b)
pwwkew: 2, 3 (wke)

Live Demo on coliru

我必须承认我同意Craig Young的意见

  

编程不是要了解错误,而不是重复&#34;。它是关于了解正在发生的状态变化,因果关系,以及何时和为什么它没有像你期望的那样做。

我试图解决这个问题(作为一个难题),假设需要某种回溯或甚至递归。所以,当我找到这个解决方案时,我终于感到惊讶了。 (一旦我开始运行,我无法拒绝发布这个作为答案。)

你如何学习制作算法?可能是,才能,可能,经验,当然还有很多实践......