Golang\Java 实现无重复字符的最长子串 - LeetCode 算法
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
示例
示例 1:
输入: s = "abcacadabcd"
输出: 4
解释: 因为无重复字符的最长子串是 "dabc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示例 4:
输入: s = ""
输出: 0
解题思路
原始字符串:abcacadabcd
Golang 代码实现
func lengthOfLongestSubstring(s string) int {
lastOccurred := make(map[byte]int)
start := 0 // 子串开始的下标
maxLength := 0 // 最大子串长度
for index, ch := range []byte(s) {
// 如果当前字符存在 map 中
//且当前字符的下标在start子串开始位置之后的,如果成立则为发生重复
// 发生重复 start 则当前字符所在的子串下标(map中的下标)后移一位
lastI, ok := lastOccurred[ch]
if ok && lastI >= start {
start = lastI + 1
}
// 计算当前字符下标(index)与 start 下标的距离
distance := index - start + 1
if distance > maxLength {
maxLength = distance
}
// key:当前字符 Ascii 码,value:当前字符下标
lastOccurred[ch] = index
}
return maxLength
}
Golang 单元测试
package main
import (
"testing"
)
// 单元测试
func TestSubStr(t *testing.T) {
tests := []struct {
s string // 传入的字符串
ans int // 答案
}{
// 定义测试数据
{"acbbbb", 3},
{"bbb", 1},
{"", 0},
{"a", 1},
{"abcde123abcde", 8},
}
for _, tt := range tests {
actual := LongNotReplace(tt.s)
// 结果不等于设定的答案
if actual != tt.ans {
t.Errorf("got %d for input %q, expected %d", actual, tt.s, tt.ans)
}
}
}
// 性能测试
func BenchmarkSubstr(b *testing.B) {
s := "acbsafaswwqabcdedg123adadwdcs"
ans := 7; // 答案
for i := 0; i < 10; i++ {
s += s
}
b.Logf("strlen:%d", len(s))
b.ResetTimer() // 重置当前执行时间,不计算上面拼接字符串
for i := 0; i < b.N; i++ {
actual := LongNotReplace(s)
if actual != ans {
b.Errorf("got %d for input %q, expected %d", actual, s, ans)
}
}
}
Java 代码实现
class Solution {
public int lengthOfLongestSubstring(String s) {
int maxLen = 0;
int start = 0;
HashMap<Character, Integer> lastOccurred = new HashMap<>();
char[] chars = s.toCharArray();
int charsLen = chars.length;
for (int i = 0; i < charsLen; i++) {
// 从 map 中获取元素,元素存在且元素出现在start开始的子串中则为重复
Integer lastI = lastOccurred.get(chars[i]);
if (null != lastI && lastI >= start) {
start = lastI + 1;
}
// 计算距离
int distance = i - start + 1;
if (distance > maxLen) {
maxLen = distance;
}
lastOccurred.put(chars[i], i);
}
return maxLen;
}
}
优化版本
// 这里使用空间换速度,使用 slice 替换 map 不涉及处理中文
// 因为使用的是byte所以 byte的空间是0~255
var lastOccurred = make([]int, 255)
func lengthOfLongestSubstring(s string) int {
//lastOccurred := make(map[byte]int)
start := 0 // 子串开始的下标
maxLength := 0 // 最大子串长度
// 将默认值修改为-1
for item := range lastOccurred {
lastOccurred[item] = -1
}
for index, ch := range []byte(s) {
//且当前字符的下标在start子串开始位置之后的,如果成立则为发生重复
// 发生重复 start 则当前字符所在的子串下标(map中的下标)后移一位
if lastI := lastOccurred[ch]; lastI != -1 && lastI >= start {
start = lastI + 1
}
// 计算当前字符下标(index)与 start 下标的距离
distance := index - start + 1
if distance > maxLength {
maxLength = distance
}
// key:当前字符 Ascii 码,value:当前字符下标
lastOccurred[ch] = index
}
return maxLength
}