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
}
分类:
Algorithm
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)