算法-字符串之最长无重复子串

作者: zero_sr | 来源:发表于2016-07-21 17:30 被阅读7544次

算法字符串系列的第四篇文章,计算给定字符串的最长无重复子串。


这篇文章主要介绍两种方法,一种是基于hash的思想,一种是基于dp(动态规划)+hash来实现,这两种方法都不难,容易理解。下面会详细介绍。

1.hash实现

这类问题应该学会分析结果的特点,比如说前面的最长回文子串,是利用了回文串的对称性,那么无重复子串呢,想到无重复,可以想到可以使用hash,当新的字符来了,有冲突,就说明前面是有重复的。
算法思想:两次循环得到所有的子串,用hash判断是否重复。

代码
代码中需要注意的地方:
1.以字符对应的ASCII码作为hash值,visit[str[i]]=0,说明str[i]这个字符还没有出现过,=1说明有重复。
2.在每次内层循环重新开始的时候,都要将visit初始化为0,每次内层循环求的是str[i...j]之间的最长子串,要判断他们之间是否有重复,所以要确保i...j这个范围内的visit都没初始化为0了,否则出现i...j之间的字符和这个范围之外的字符重复就会导致结果出错。

/*求所有的子串,用hash判断是否是重复的,*/
void LNRS_hash(char *str, int size)
{
    int i, j;
     for (i = 0; i < size; ++i)
    {
        memset(visit, 0, sizeof(visit));//初始化visit为0
        visit[str[i]] = 1;
        for (j = i + 1; j < size; ++j)
        {
            if (visit[str[j]] == 0)
            {
                visit[str[j]] = 1;
            }
            else
            {
                if (j - i > longest)
                {
                    longest = j - i;
                    start = i;
                }
                break;
             }
        }
        if ((j == size) && (j - i > longest))
        {
            longest = j - i;
            start = i;
        }
    }
}

结果:

基于hash求最长无重复子串

2.动态规划+hash

首先理解,动态规划算法的思想,将问题分解为子问题的解,找到重叠子问题和最优子结构,对需要重复计算的结果进行存储。在这里最优子结构很好理解,在所有无重复子串中,长度最长的就是最优的。而重叠子问题呢?简单的理解,就是当前的LNRS串可以由上一次计算的LNRS得到。

重叠子问题:我们考虑两种情况。

  1. 当前的字符和前面的字符没有重复,那么到当前字符的最长无重复子串就应该在上次求得的LNRS串长度+1,;
  2. 如果当前的字符有冲突,那么有两种情况需要分析。第一,如果和它冲突的字符在当前最长无重复子串的起始位置前面,那么很明显,对计算当前的LNRS串没有影响,还是在上次基础上+1;如果冲突字符在当前的LNRS串开始位置之后,那么就从后一个位置计算无重复子串的长度。

而hash在这里就是帮助我们判断是否重复,而不用回溯子串。

代码
理解了上面提到的重叠子问题之后,下面的问题就简单多了。
代码中需要注意的地方:

  1. dp[]记录第i位的无重复子串,这个子串不一定是全局最长子串,但是针对第i个字符是最长的。所以需要比较所有的dp[i],来确定最长的。
  2. visit[i]在这里不止是当做hash来使用了,它不止用来判断是否重复,还记录最近的重复位置。eg:abcdahijka,针对最后一个a,visit[a]记录的应该是第二个a的位置,记录第一个a的位置毫无意义,因为从第一个a后面的b...到最后一个a之间,还有一个a,所以其实b到第二个a之间的字符肯定不会在a3的最长重复子串内。
/* LNRS dp + hash 记录下标 */
void LNRS_dp_hash(char * str, int size)
{
    int *dp = (int*)malloc(sizeof(int)*size);

    memset(visit, -1, sizeof(visit));
    memset(dp, 0, sizeof(dp));
    dp[0] = 1;
    visit[str[0]] = 0;
    int last_start = 0;

    for (int i = 1; i < size; i++) {
        if (visit[str[i]] == -1){
            dp[i] = dp[i - 1] + 1;
            visit[str[i]] = i;//记录字符的下标
        }
        else {/*和visit[str[i]]位置的字符冲突*/
            if (last_start <= visit[str[i]])
            {
                dp[i] = i - visit[str[i]];
                last_start = visit[str[i]] + 1;
                visit[str[i]] = i;//更新最近的重复位置
          }
            else{
                dp[i] = dp[i - 1] + 1;
                visit[str[i]] = i;//记录字符的下标
            }
        }

        if (dp[i]>longest)
        {
            longest = dp[i];
            start = i - longest + 1;
        }
    }
}

结果:

dp+hash最长无重复子串

3.dp+hash优化的问题

我们看dp[i] = dp[i-1]+1;可以理解为就是在更新当前i位的最优解,在看代码中更新dp[i]的部分,再使用到dp[i-1]的地方都只是在上一次的基础上+1,看到这里我们就很容易做出优化策略了。可以不用n位长的数组dp[i]来存储当前的最优解,而只用一个变量来记录就可以了,优化方案很简单,就不贴代码了。
优化:用一个变量来代替dp[]。

总结:

最长回文子串的问题:关注子串中的对称关系。
最长无重复子串为题:关注子串中字符的唯一性,善用hash。
动态规划法,对需要重复计算的问题,可以选保存下来,减少计算的时间复杂度。

相关文章

  • 文章收藏

    iOS面试题系列之常见算法 排序算法整理 字符串【3】最长回文子串【3】最长无重复子串【1*】字符串转数字【4】K...

  • iOS面试题汇总---算法类

    字符串 【3】最长回文子串 【3】最长无重复子串 【1*】字符串转数字 【4】KMP 算法 【2】字符串全排列 【...

  • 算法-字符串之最长无重复子串

    算法字符串系列的第四篇文章,计算给定字符串的最长无重复子串。 这篇文章主要介绍两种方法,一种是基于hash的思想,...

  • [Leetcode][3][longest substring

    题目描述: 最长连续无重复子字符串Example 1: Input: "abcabcbb"Output: 3Exp...

  • 算法1-无重复字符的最长子串

    无重复字符的最长子串 首先分析一下题目,求给定字符串的最长不重复子串,思路应该是分治不断降规模,把长度为n的字符串...

  • 【leetcode3】 3. Longest Substrin

    关键字:最长不重复子串、双指针 难度:Medium 题目大意:求一个字符串最长不重复子串的长度 题目: Given...

  • 最长不重复子串

    1. 问题定义 最长不重复子串:一个字符串中最长的没有重复字符的子串。举个? : abcabcbb 最长子串 a...

  • 3、Longest SubString Without Repe

    Examples:找出最长无重复子串长度Given "abcabcbb", the answer is "abc"...

  • Python编程题16--最长不重复子串

    题目 给定一个字符串,请从这个字符串中找出所有最长的没有重复字符的子串,并返回最长不重复子串的长度。 例如:字符串...

  • 【python】求一个串中出现的第一个最长重复子串?

    题目:给定一个字符串,找出这个字符串中最长的重复子串,比如给定字符串“banana”,子字符串“ana”出现2次,...

网友评论

  • f6bc90fe7920:完整的代码有吗,visit longest定义
  • 郑明明:写的还是不错的,理解起来很舒服
    zero_sr: @NtZheng 谢谢支持~

本文标题:算法-字符串之最长无重复子串

本文链接:https://www.haomeiwen.com/subject/mfybjttx.html