面试题48:最长不含重复字符的子字符串

题目:

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符串中只包含a~z的字符。例如,在字符串“arabcacfr”中,最长的不含重复字符的子字符串是“acfr”,长度为4。

分析:

我们定义函数f(i)表示以第i个字符为结尾的,不包含重复字符的子字符串的最长长度。我们从左到右逐一扫描字符串中的每个字符。当我们计算第i个字符为结尾的不包含重复字符的子字符串的最长长度f(i)时,已经知道f(i-1)了。

如果第i个字符之前没有出现过,那么f(i)=f(i-1)+1。例如,在字符串“arabcacfr”中,显然f(0)=1,在计算f(1)时,下标为i的字符串r之前没有出现骨偶,因此f(1)=f(0)+1=2。继续向后遍历。

如果第i个字符之前出现过,情况就要复杂一点了。先计算第i个字符和它上次出现在字符串中的位置的距离,记为d,分两种情况讨论。

第一种情况:如果d≤f(i-1),此时第i个字符出现在f(i-1)的最长子字符串中,因此f(i)=d。此时第i个字符出现两次所夹的子字符串中再也没有其他重复字符。再来看f(2),下标为2的字符是a,在前面出现过,上一次是下标为0的位置,此时d=2-0=2,上次重复的字符在f(1)对应的最长不含重复子字符串中,所以f(2)=d=2,对应最长不含重复字符的子字符串是“ra”。

第二种情况:如果d>f(i-1),此时第i个字符上次出现在f(i-1)对应的最长不包含重复字符的子字符串之前,因此f(i)=f(i-1)+1。接着以字符串“arabcacfr”分析,求最后一个字符r为结尾的最长不包含重复字符的子字符串的长度,即求f(8),可以知道f(7)对应的最长不含重复子字符串是“acf”,f(7)=3,再去找上一次r出现的位置,发现在下标为1的位置,此时d=8-1=7>f(7)。上一个字符r不在f(7)对应的字符串“acf”中,此时把r直接拼接到“acf”后面也不会出现重复字符,因此f(8)=f(7)+1=4,对应最长不含重复字符的子字符串是“acfr”。

解法:

package com.wsy;

public class Main {
    public static void main(String[] args) {
        char[] chars = "arabcacfr".toCharArray();
        getLongestSubstringWithoutDuplication(chars);
    }

    public static void getLongestSubstringWithoutDuplication(char[] chars) {
        int[] position = new int[26];// 用来存储某个字符上一次出现的下标
        int length = chars.length;
        for (int i = 0; i < 26; i++) {
            position[i] = -1;// 初始化上一次出现位置为-1,表示从来没有出现过
        }
        int currentLength = 0;
        int maxLength = 0;
        for (int i = 0; i < length; i++) {
            int previousIndex = position[chars[i] - 'a'];
            if (previousIndex < 0 || i - previousIndex > currentLength) {
                currentLength++;
            } else {
                currentLength = i - previousIndex;
            }
            position[chars[i] - 'a'] = i;
            if (currentLength > maxLength) {
                maxLength = currentLength;
            }
        }
        System.out.println("最长不包含重复字符的子字符串长度是" + maxLength);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值