LeetCode刷题笔记 3 / 剑指Offer 48(涉及到哈希表)

题目:
给定一个字符串,找出最长的没有重复字符的子字符串的长度。
在这里插入图片描述
我的答案:(Java)

1.暴力法:
(算历重复,eg:abcbd, 判断完abcb重复后,bcb…,cb…都不用再重复判断)

public int lengthOfLongestSubstring(String s) {
    int len = s.length();
    int n = 0;
    if (len <= 1){
        return len;
    }
    outer: for(int i = 0; i < len-1; i++) {
        for(int j = i+1; j < len; j++){
            for(int k = i; k < j; k++){
                if(s.charAt(j) == s.charAt(k)){
                    n = Math.max(n,j-i);
                    continue outer;
                }
                if(k == j-1){
                    n = Math.max(n,j-i+1);
                }
            }
        }
    }    
    return n;
}

2.哈希表

整体思路:
建立哈希表,依次遍历字符串中的字符,哈希表中有则去掉对应位及之前的键值,没有则按续加入哈希表。

public int lengthOfLongestSubstring(String s) {
    int len = s.length();
    int n = 0;
    int lastTimeFlag = 0;
    int thisTimeFlag = 0;

    Map<Character,Integer> map = new HashMap<>();
    for(int i = 0; i < len; i++){
        if(map.containsKey(s.charAt(i))) {
            thisTimeFlag = map.get(s.charAt(i));
            for(int j = lastTimeFlag; j <= thisTimeFlag; j++){
                map.remove(s.charAt(j));
            }
            lastTimeFlag = thisTimeFlag + 1;
        }
        map.put(s.charAt(i),i); 
        n = Math.max(map.size(),n);
    }       
    return n;
}

参考答案后优化:

将字符放入哈希表中,如果哈希表中包含了该字符,则更新计算长度的开始位置,更新哈希表,每次更新最大长度。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character,Integer> map = new HashMap<>();
        int len = s.length();
        int maxLen = 0;
        int begin = -1;
        for(int i = 0; i < len; i++) {
            if(map.containsKey(s.charAt(i))) {
                begin = Math.max(begin,map.get(s.charAt(i)));
            } 
            map.put(s.charAt(i),i);
            maxLen = Math.max(maxLen,i-begin);
        }
        return maxLen;
    }
}

答案:
方法一:遍历所有子字符串,在没有重复字符的字符串里寻找最大长度。
时间复杂度O(n3)
方法二:采用开始和结束索引定义滑动窗口

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;
    }
}

时间复杂度O(2n) = O(n)
空间复杂度O(min(m,n))

答案三:滑动窗口优化,不是令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;
    }
}

时间复杂度O(n)
空间复杂度O(min(m,n))

需要注意的地方:

  1. 哈希表及字符串相关方法要抄对(如.containsKey())
  2. 滑动窗口的思想
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值