力扣算法第三题-无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

经过一次线上笔试,发现自己直接写代码的能力严重不足,所以这次就先在网页上编写代码,不借助eclipse工具,慢慢练习
然后就从每次的错误开始说起吧。

try1

发现自己挺多小毛病的String的charAt方法写成CharAt,然后长度就直接是 s.length ,实际上是 s.length()

class Solution {
    public static int lengthOfLongestSubstring(String s) {
        int cout = 0;
        int temp = 0;
        int i = 0;
        int j = 0;
        for(i = 0;i<s.length();i++){
            for(j = i+1;j<s.length();j++){
                if(s.charAt(i)!=s.charAt(j)){
                    cout++;
                    continue;
                }else{
                    temp = cout>temp?cout:temp;
                    cout = 0;
                    break;
                }
            }
                        if(j == s.length()){
                temp = cout>temp?cout:temp;
                 break;
            }
        }
        return temp;
    }
}

这是一开始流程图都没画直接写的,想法是第i个字符与后面第j(j自增)个字符逐个比较。后来一想,很明显错了,因为假设第一个字符和第一二三四五个字符比较,第一个字符和第六个字符相同,但是中间的字符却没有相互比较,如果第二三个字符相同,就断了,所以错了。

try2

所以就开始画流程图啦,想想,应该要有三个循环,开始字符的循环一个,然后最后字符循环一个,然后中间字符循环一个。

Created with Raphaël 2.2.0 开始 计数初始化: cout=0;temp=0, i=0;j=0;k=0; j=i+1;k=i; (i) = (j)? cout = j-i; cout>temp? temp = cout; i = j; k = j-1? j++; k++; (k)=(j)? cout = k-i; cout>temp? temp=cout; i = k+1; yes no yes no yes no yes no yes no
class Solution {
    public int lengthOfLongestSubstring(String s) {
        int cout = 0;
        int temp = 0;
        int i = 0;
        int j = 0;
        int k = 0;
 //       for(i = 0;i<s.length();i++)
        while(i<s.length()){
            for(j = i+1;j<s.length();j++){
                k = i;
                if(s.charAt(i)!=s.charAt(j)){
                    while(k != j-1){
                        k++;
                        if(s.charAt(k) != s.charAt(j)){
                            continue;
                        }
                        else{
                            cout =k-i;
                            temp = cout>temp?cout:temp;
                            i = k+1;
                            break;
                        }
                    }
/*                    if(k == j-1){
                        continue;
                    }
*/
                }else{
                    cout = j-i;
                    temp = cout>temp?cout:temp;
                    i = j;
                    break;
                }
            }
            if(j == s.length()){
                break;
            }

        }
/*            if(s.length() <= 1){
                temp = s.length();
            }
*/        return temp;
    }
}

try(n)(right)

人生艰难啊,力扣的题做到心态爆炸,每一次以为成功了,结果又出了一个问题,最好靠着debug一点点分析,才终于做成。不多说,上代码

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int cout = 0;
        int temp = 0;
        int i = 0;
        int j = 0;
        int k = 0;
 //       for(i = 0;i<s.length();i++)
        while(i<s.length()){//开始字符
            for(j = i+1;j<s.length();j++){//最后字符
                k = i;
                if(s.charAt(i)!=s.charAt(j)){//开始字符与最后字符比较
                    while(k != j-1){
                        k++;
                        if(s.charAt(k) != s.charAt(j)){//中间字符与最后字符比较
                            continue;
                        }
                        else{
                            cout =k-i+1;
                            temp = cout>temp?cout:temp;
                            int x = 0;
                            for(x = k+1;x<=j;x++){
                                if(s.charAt(k)!=s.charAt(x)){
                                //和最后字符相同的中间字符与中间字符、最后字符之间的字符比较
                                    continue;
                                }
                                else{
                                    cout = x-i; 
                                    temp = cout>temp?cout:temp;
                                }
                            }
                            i = k+1;
                            break;
                        }
                    }
//                    if(k == j-1) {
//                    	continue;
//                    }
                }else{
                    cout = j-i;
                    temp = cout>temp?cout:temp;
                    i++;
                    break;
                }
            }
            if(j == s.length()){
            	cout = j-i;
                temp = cout>temp?cout:temp;
                i = j;
                break;
            }

        }
       return temp;
    }
}

问题

因为中间尝试了很多,改了很多次代码,就不一一上代码了,主要说说碰到的问题

1.问题: 最外层while循环没有break,直接导致风扇疯狂转啊转,死循环,没得出来,
解决方法:加上个break的条件再break
2. 上面的流程图没法看,自己画的更丑,但毕竟辛辛苦苦画出来的,即使有点错,也放上去吧
在这里插入图片描述
3.问题: 一条字符串全是不同字符的情况,最后因为画的流程图里没有赋值,得出的结果居然是0
解决方法:就是最外层循环break的条件了,(j-i);
4. 问题:abcb型,只能得个2出来,因为(1)和(3)相同,直接就跳到k-i+1(这里算的是i到k之间的字符数),算完之后直接break了,没算后面的
解决方法:在break之前再加个循环,加个条件,用来比较第k个字符后第k个到第j字符间是否相同,比较得到的数减去一开始(i)的数,与temp比较,决定是否放入答案temp中
5. 问题:dvdf型,也是只能得出2个出来,原因是直接跳到i=j上了,没有把i逐个循环(好像这样的话也可以一开始就用for的i循环?)
解决方法:把第二层循环break前的i =j换成i++;

小结

做到心态炸,最后还是用debug一点一点的修正了答案,但是我的方法好像不太好,
在这里插入图片描述
时间复杂度和空间复杂度都挺差= =!虽然一开始画的图就能解决三个例题,但是不够全面,后来用了三四个小时才终于解决问题。
还是得认真学,多多的练哇。

题解

有点惭愧,学了那么久Java,还是停留在C语言的思想上,没有真正运用到Java的面向对象思想。应当注意

暴力法

  • 要检查一个字符串是否有重复字符,我们可以使用集合。我们遍历字符串中的所有字符,并将它们逐个放入 set 中。在放置一个字符之前,我们检查该集合是否已经包含它。如果包含,我们会返回 false。循环结束后,我们返回 true。
public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int ans = 0;
        for (int i = 0; i < n; i++)
            for (int j = i + 1; j <= n; j++)
                if (allUnique(s, i, j)) ans = Math.max(ans, j - i);
        return ans;
    }

    public boolean allUnique(String s, int start, int end) {
        Set<Character> set = new HashSet<>();
        for (int i = start; i < end; i++) {
            Character ch = s.charAt(i);
            if (set.contains(ch)) return false;
            set.add(ch);
        }
        return true;
    }
}

滑动窗口

意思就是先令i=j=0,然后开始 j 递增,直至有重复的出现(用Set的contains()方法),然后 递增 i,若还是重复,则窗口开始滑动。 如果一开始就遇到最长长度,那么 i 和 j同时递增【即窗口滑动】,直至j等于字符串长度。

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        Set<Character> set = new HashSet<>();
        int ans = 0, i = 0, j = 0;
        while (i < n && j < n) {
            // try to extend the range [i, j]
            if (!set.contains(s.charAt(j))){
                set.add(s.charAt(j++));
                ans = Math.max(ans, j - i);
            }
            else {
                set.remove(s.charAt(i++));
            }
        }
        return ans;
    }
}

优化的滑动窗口

在滑动窗口基础上,检测到重复的字符的位置 j’,然后直接把i设置成 j’+1,而不用i递增。

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length(), ans = 0;
        Map<Character, Integer> map = new HashMap<>(); // current index of character
        // try to extend the range [i, j]
        for (int j = 0, i = 0; j < n; j++) {
            if (map.containsKey(s.charAt(j))) {
                i = Math.max(map.get(s.charAt(j)), i);
            }
            ans = Math.max(ans, j - i + 1);
            map.put(s.charAt(j), j + 1);
        }
        return ans;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值