leetcode 3 Longest Substring Without Repeating Characters

第三题我写的程序虽然AC了,但在时间上表现不好, 随后在该题的Discuss中找到一个别人写的12行的4ms代码, 感觉方法比我的更巧妙, 所以秉着学习的态度,我这里写一点我对他代码的理解. 最后也附上我的代码. 12行代码的原帖地址:https://leetcode.com/discuss/49128/4ms-c-code-in-12-lines

int lengthOfLongestSubstring(char* s) 
{
    int length = 0;
    char *end = s, *temp;
    char *addressTable[128] = {NULL};

首先初始化length为0, length表示最长的不含重复字符的字串的长度. end指针表示当前检查到的最后一个字符. temp指针则用于指向一对重复字符中的第一个字符. addressTable是一个Hash表, 其中每个索引值对应的是字符的ascii码, 而表中的每一项对应的是一个指针, 指向的是对应字符在目前已检测的字符串中最后出现的位置. 例如: abcad, a在addressTable中对应的位置就是addressTable[97], 因为a的ascii码就是97,addressTable[97]其实就是一个指向a最后出现位置的指针,例如当我们检查到c时,addressTable[97]指向的是a bcad,而当我们检查到d时,addressTable[97]指向的是abc a d. 将addressTable全部初始化为NULL, 此时addressTable中每一项都是NULL, 即存的值为0.

    while(*end)
    {
        temp = addressTable[*end];
        addressTable[*end] = end;
        if(s <= temp)
        {
            length = length<end-s?end - s : length;
            s = temp + 1;
        }
        end++;
    }

这个循环就是这个算法的核心, 首先while条件判断, 当前end是否已经遍历了整个字符串. 如果是, 那么退出, 如果不是, 那么继续遍历. 首先第一步, 用end指向的字符上一次在字符串中出现的位置, 用temp指向那个位置, 如果该字符之前没有出现过, 那么就是NULL. 由于end指向的字符是该字符在字符串中最新的一次出现,所以需要把addressTable中的该字符对应的指针进行更新,指向当前位置,即end指向的位置。接下来判断s和temp的大小,s表示的是当前正在检查的无重复字符子串的起始位置。temp表示的是重复字符对中的第一个字符位置,如果它小于s,表示它在当前无重复字符子串之前,所以添加end指向的字符后,这个子串仍然没有重复。值得一提的是,如果end指向的字符之前没有在字符串中出现过,那么temp就为NULL(值为0),所以必然小于s,因此满足小于s就不会重复的判断。如果大于等于s,那么添加end指向的字符后,这个重复字符对就位于该子串中了,所以不能添加添加end指向的字符,因此当前子串不能再增长了,我们就把这个子串的长度(即end-s)与这个子串之前的所有子串的最长长度length比较,来求出包含这个子串的所有子串的最长长度,并保存到length中。然后我们更新s为下一个子串的起始位置,值得注意的是我们是把s更新到当前重复字符对的第一个字符的下一个,例如:abcdecf,我们找到第一个重复字符对c de c, 此时s指向的是a,我们找到的不重复子串为:abcde,我们更新s位置时,应把s更新到d,因为如果更新到b或c,新子串必然到第二个c时就无法再增长,因此得到的不重复子串为bcde和cde,必然比abcde短,而我们要找的是最长不重复子串,因此更新到b和c没有意义。之后end再往后移,继续检查下一个。

    length = length < end - s ? end -s : length;
    return length;
}

因为前面的检查方式都是出现了重复再去计算子串长度,但这忽略了一个问题,就是如果没有重复,但字符串结束了,那么这个子串也必然结束,这种情况下产生的子串也可能是最长的,所以我们还要单独计算到字符串末的这个无重复字符子串的长度,然后与当前最长长度比较,得到的结果就是整个字符串中最长无重复字符子串的长度。

下面是我自己方法的完整代码

#include <iostream>
#include "stdlib.h"
#include "string.h"
using namespace std;

int lengthOfLongestSubstring(char* s) 
{
    int length = 0;
    char *end = s, *temp;
    char *addressTable[128] = {NULL};
    while(*end)
    {
        temp = addressTable[*end];
        addressTable[*end] = end;
        if(s <= temp)
        {
            length = length < end - s ? end - s : length;
            s = temp + 1;
        }
        end++;
    }
    length = length < end - s ? end -s : length;

    return length;
}

int main()
{
    int length;
    cout<<"input the length of the string:"<<endl;
    cin>>length;
    char *string = (char*)malloc(sizeof(char) * (length+1)); //+1 for \0

    for(int i = 0; i < length; i++)
    {
        cin>>string[i];
    }

    string[length] = '\0';
    //cout<<string<<endl;;

    cout<<lengthOfLongestSubstring(string);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值