最长不含重复字符的子字符串

题目
输入一个字符串(只包含a-z的字符)。求其最长不含重复字符的子字符串的长度。例如,对于arabcacfr,最长不含重复字符的子字符串为acfr,长度为4。
解题思路
(1) 动态规划,用f(i)表示以i个字符结尾不包含重复子字符串的最长长度,从左往右扫描
1.若第i个字符在之前没有出现过,则f(i)=f(i-1) + 1
2.若第i个字符在之前出现过,计算第i个字符距离上次出现之间的距离为d
(1) 若d <= f(i-1),则说明第i个字符上次出现在f(i-1)对应的不包含重复字符的字符串之内,那么这时候更新f(i)=d
(2) 若d > f(i-1),则无影响,f(i) = f(i-1) + 1
分析arabcacfr
f(0) = 1, a
f(1) = 2, ar
f(3) = 2, ra, 因为d=2, f(1) = 2, 所以上一个a在 f(1) 之中
f(3) = 3, rab
f(4) = 4, rabc
f(5) = 3, bca,因为d=3,f(1)=4,所以上一个a一定在f(4)中
f(6) = 2, ac
f(7) = 3, acf
f(8) = 4, acfr,因为d=7,f(7)=3,因此上一个r不在f(7)中,f(8) = f(7) + 1
源代码

package Arithmetic;

import java.util.Arrays;

public class LongestSubString {
    public static void main(String[] args) {
        System.out.println(lengthOfLongestSubString("arabc"));
    }

    //动态规划
    private static int lengthOfLongestSubString(String str) {
        int curLength = 0;//当前长度
        int maxLength = 0;//最大长度
        int[] position = new int[26];//保存当前字符是否出现过
        Arrays.fill(position, -1);//-1表示没出现过
        for (int i = 0; i < str.length(); i++) {
            //这里用到a~z分别用0~25下标存,所以当一个a出现的时候,只需要计算其a-'a'这个位置的下标
            //即可判断是否出现过,如果出现过,则将这个值存储下来
            int prevIndex = position[str.charAt(i) - 'a'];
            //字符串"arabcacfr"
            //如果在之前没有出现过,或者出现过但是在前一个不重复子串的前面,比如上面的字符串,最后一个r
            //因为当前的最长子串是acf,而r前一次出现还是在这个子串之前,所以还是等于子串加1
            if (prevIndex < 0 || i - prevIndex > curLength) {
                curLength++;
            } else {//如果在之前出现过,且前面的最长不重复子串之前
                if (curLength > maxLength)//因为不在重复子串之间,所以当前不重复的最长子串为两个字符之间i-prevIndex
                    maxLength = curLength;
                curLength = i - prevIndex;
            }
            position[str.charAt(i) - 'a'] = i;
            if (curLength > maxLength)
                maxLength = curLength;
        }
        return maxLength;
    }
}

(2) HashMap
源代码

import java.util.HashMap;

public class LongestNonRepeatingSubStr {
    private static int LongestNonRepSubStr(String string) {
        int maxLen = 0;//保存最长不重复子串的长度
        int left = -1;
        if (string == null || string.length() == 0)
            return maxLen;
        HashMap<Character, Integer> map = new HashMap<>();//HashMap存储字符及对应的下标
        for (int i = 0; i < string.length(); i++) {
            char c = string.charAt(i);
            if (map.containsKey(c) && map.get(c) > left)
                left = map.get(c);
            map.put(c, i);
            maxLen = Math.max(maxLen, i - left);
        }
        return maxLen;
    }

    public static void main(String[] args) {
        System.out.println(LongestNonRepSubStr("arabcacfr"));
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值