题目
演示例题为leetcode题目中一道经典题目
Longest Substring Without Repeating Characters
即在一个字符串中寻找最大不重复子串 已有针对Java例题,使用go语言实现,并进行优化
例如:
Input: "abcabcbb"
Output: 3
Input: "bbbbb"
Output: 1
Input: "pwwkew"
Output: 3
方法一:Java举例方法:穷举
暴力法,逐步检查所有的子字符串,找到最大不重复子字符串
时间复杂度:O(n^3)
空间复杂度:O(min(m,n)), 需要O(K)的空间,其中K表示set的大小,取决于字符串n的大小以及字符集/字母m的大小。
public static int lengthOfLongestSubstring1(String s) {
int n = s.length();
int ans = 0;
String maxson = null;
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);
if (j - i > ans) {
ans = j - i;
maxson = s.substring(i, j);
}
}
}
}
System.out.println(maxson);
return ans;
}
public static boolean allUnique(String s, int start, int end) {
Set<Character> set = new HashSet<>();
for (int i = start; i < end; i++) {
Character c = s.charAt(i);
if (set.contains(c)) {
return false;
}
set.add(c);
}
return true;
}
不论是在时间复杂度上,还是空间复杂度上,穷举都过于浪费资源,由此引出第二种方法
方法二 使用go语言解决
时间复杂度:O(2n) = O(n),在最糟糕的情况下首尾都访问了n次 。
空间复杂度:O(min(m,n)),滑动窗口需要O(K)的空间,其中K表示set的大小, 取决于字符串n的大小以及字符集/字母m的大小。
func lengthOfLongestSubstring2(s string) int {
if len(s) == 0 {
return 0
}
var freq [127]int
result, left, right := 0, 0, -1
for left < len(s) {
if right+1 < len(s) && freq[s[right+1]] == 0 {
freq[s[right+1]]++
right++
} else {
freq[s[left]]--
left++
}
result = max(result, right-left+1)
}
return result
}
代码分析
- 滑动窗口先判断输入的字符串长度不为
- 滑动窗口左侧为left,右侧为right
- 逐个接收字符,并判断
1)窗口右侧是否溢出
2)传入元素是否已经在freq内- 如果传入的元素不在freq中出现过,则标记出现,即将freq对应的元素置为1
- 如果传入的字符在freq中已经存在,则证明最左侧就是重复元素
- 窗口接收元素,同时删除最左侧元素
- 使用result接收 当前窗口与result 中的最大值
- 回到第二步继续判断,直到遍历字符串中的每一个元素
- 输出result
心得体会
解题步骤
第一步 应该将问题拆解成片段
第二步 将片段由代码实现
第三步 扩充片段,解决问题 第四步 优化代码,寻找更优解
对于枚举能够解决的问题,首先应该将问题使用枚举实现,再优化
对于任意代码,时间复杂度与空间复杂度往往不可兼得,在运行时可以优先降低其中一个,然后再去寻找更优解