剑指offer16:不含重复字符的最大字符串

题目:
输入一个字符串,求该字符串中不含重复字符的最长子字符串的长度。例如,输入字符串“babcca”,其最长的不含重复字符的子字符串“abc”,长度为3。
分析:
该题还是利用哈希表和指针,不同的是该题不是求变位词,而是求不重复的最长子字符串,思路稍微转变,思路就是开始将两个指针都指向字符串的第一个位置,然后第二个指针右移字符串,两个指针之间的子字符串如果没有重复接着右移右边的指针一个单位,如果有重复右移左边指针一个单位,反复此操作,指针移动实例看下图。
在这里插入图片描述
一个子字符串不含重复的字符,那么每个字符都只出现一次,在哈希表对应的值就是1,没有在子字符串中出现的其他字符对应的值都是0,也就是说如果子字符串中不含重复字符串,那么它对应的哈希表没有比1大的值。
而且还需要注意该题没有说明字符串中只包含英文字母,那么就有可能包含数字或其他字符,因此字符就可能不止26个,由于ASCII码总共有256个字符,因此用来模拟哈希表的数组长度是256。
代码如下:

public class LengthOfLongestSubstring {
    public static void main(String[] args) {
        String s = "babcca";
        int i = lengthOfLongestSubstring(s);
        System.out.println(i);
    }
    public static int lengthOfLongestSubstring(String s){
        if (s.length() ==0){
            return 0;
        }
        int[] counts = new int[256];
        int i = 0;
//        左指针j初始值为-1
        int j = -1;
        int longest = 1;
        for (; i <s.length(); i++) {
            counts[s.charAt(i)-'0']++;
//            有重复的,左指针右移
            while (hasCreaterThan1(counts)){
                counts[s.charAt(++j)-'0']--;
            }
            longest = Math.max(longest,i-j);
        }
        return longest;
    }

    private static boolean hasCreaterThan1(int[] counts) {
        for (int count : counts) {
            if (count>1){
                return true;
            }
        }
        return false;
    }
}

在这里插入图片描述
该算法时间复杂度为O(n),但需要注意的是该算法每次都可能扫描一次数组counts,counts的长度是常数256,这个常数有点大,因此可以优化下该算法。
设置一个变量countDup来记录字符串中重复字符的个数,如果一个字符对应的数字从1变为2说明该字符重复了,countDup加1,重复了所以右移第一个指针,删除子字符串最左边的字符,把哈希表对应的数字减1,当字符对应的数字由2变成1时,该字符不再重复出现,变量countDup减1,避免了多次重复扫描数组counts,时间效率有所提高。

public class LengthOfLongestSubstring {
    public static void main(String[] args) {
        String s = "babcca";
        int i = lengthOfLongestSubstring(s);
        System.out.println(i);
    }
    public static int lengthOfLongestSubstring(String s){
        if (s.length() ==0){
            return 0;
        }
        int[] counts = new int[256];
        int i = 0;
//        左指针j初始值为-1
        int j = -1;
        int longest = 1;
//        定义变量countDup用来存储哈希表大于1的数字的个数,也就是子字符串中重复字符的个数
        int countDup = 0;
        for (; i <s.length(); i++) {
            counts[s.charAt(i)-'0']++;
            if (counts[s.charAt(i)-'0']==2){
                countDup++;
            }
//            有重复的,左指针右移
            while (countDup>0){
//                右移第一个指针删除子字符串中最左边字符
                counts[s.charAt(++j)-'0']--;
//                直到一个字符对应的数字由2变成1,该字符串不再重复出现,countDup-1
                if (counts[s.charAt(j)-'0']==1){
                    countDup--;
                }
            }
            longest = Math.max(longest,i-j);
        }
        return longest;
    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙崎流河

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值