LeetCode 3: 无重复字符的最长子串(Longest Substring Without Repeating Characters)解法汇总


更多LeetCode题解

MySolution

class Solution {
public:
	int lengthOfLongestSubstring(string s) {
		int res = 0;
		for (int i = 0; i < s.size(); i++) {
			vector<char> v;
			for (int j = i; j < s.size(); j++) {
				if (find(v.begin(), v.end(), s[j]) != v.end()) break;
				v.push_back(s[j]);
				if (v.size() +1 > res) res = v.size();
			}
		}

		return res;
	}
};

注意点

第一次提交挂了:

  • 没有考虑空字符的情况,直接将res置1了,这样的话j初始不能初始化为i+1,否则无法正确处理单个字符的情况。

java

  • 看了官方解答发现我的解法就是Approach 1: Brute Force暴力法,那就看看官方的java代码吧
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;
    }
}

Approach 2: Sliding Window

java

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

C++

class Solution {
public:
	int lengthOfLongestSubstring(string s) {
		int i = 0, j = 0;
		int res = 0;
		unordered_set<char> existed;
		while (j < s.size()) {
			if (!existed.count(s[j])) {
				existed.insert(s[j++]);
				res = max(res, j - i);
			}
			else {
				existed.erase(s[i++]);
			}
		}
		return res;
	}
};

思想

方法的精髓就在于左游标i与右游标j,右游标不断右移,并将指向的字符不断存入任意的容器,一旦发现容器中已经存在的字符,则将容器中此字符删除,并将左游标右移一位。

为什么滑窗的复杂度就低下来了呢?

In the naive approaches, we repeatedly check a substring to see if it has duplicate character. But it is unnecessary. If a substring s i j s_{ij} sij from index i i i to j − 1 j-1 j1 is already checked to have no duplicate characters. We only need to check if s [ j ] s[j] s[j] is already in the substring s i j s_{ij} sij.To check if a character is already in the substring, we can scan the substring, which leads to an O ( n 2 ) O(n^2) O(n2) algorithm. But we can do better.By using HashSet as a sliding window, checking if a character in the current can be done in O ( 1 ) O(1) O(1).

Approach 3: Sliding Window Optimized

java

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

C++

class Solution {
public:
	int lengthOfLongestSubstring(string s) {
		int res = 0;
		unordered_map<char, int> existed;
		for (int i = 0, j = 0; j < s.size(); j++) {
			if (existed.find(s[j]) != existed.end()) {
				i = max(i, existed[s[j]]);
			}
			existed.insert_or_assign(s[j], j + 1);//C++17 at least
			res = max(res, j - i + 1);
		}
		return res;
	}
};

思想

使用一个hashmap存放每个字符的下一个字符的下标,一旦遇到已经出现过的字符,则更新左游标为hashmap中存放的值(即上一个此字符的下一字符位置),且更新hashmap中此字符的值。

假设是ASCII字符集

此方法与hashmap法完全一样,只不过通过空间换取时间,新建一个含有128个元素的数组,128即ASCII字符集的字符数。用数组存放上一种方法中用hashmap存放的值。

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length(), ans = 0;
        int[] index = new int[128]; // current index of character
        // try to extend the range [i, j]
        for (int j = 0, i = 0; j < n; j++) {
            i = Math.max(index[s.charAt(j)], i);
            ans = Math.max(ans, j - i + 1);
            index[s.charAt(j)] = j + 1;
        }
        return ans;
    }
}
class Solution {
public:
	int lengthOfLongestSubstring(string s) {
		int res = 0;
		int existed[128] = { 0 };
		for (int i = 0, j = 0; j < s.size(); j++) {
			if (existed[s[j]]) i = max(i, existed[s[j]]);
			existed[s[j]] = j + 1;
			res = max(res, j - i + 1);
		}
		return res;
	}
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值