字符串最长不重复子串 java_最长不重复子串问题

本文介绍了如何使用Java解决字符串中最长不重复子串的问题,包括两种解法:双指针滑动窗口和改进版滑动窗口。详细解析了每种方法的思路和实现代码,以及复杂度分析。
摘要由CSDN通过智能技术生成

经典问题,记录一下这道题解法

问题描述

给定一个字符串,找到最长子串的长度,要求子串不含不重复字符。

样例

给定"pwkpwo"的答案是是4("kpwo")。

给定"bbbbb"的答案是1("b")。

解法

1.双指针-滑动窗口

i:表示窗口左端点

j:表示窗口右端点

set存储s[i]到s[j]间的字符

如果没有重复字符,那么将当前窗口大小与目前最长的子串长度比较并更新,j++;

如果有重复字符,那么将窗口左端点右移,i++,直到窗口内不含重复字符,执行上一行

复杂度:

遍历一遍字符串s为O(n),而set里极端情况下也只存128个字符,所以插入删除是O(1)的,总的复杂度就是O(n)

public class Solution {

public int lengthOfLongestSubstring(String s) {

int n = s.length();

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

}

}

2.改进版滑动窗口

相比于上一种方法,改良的代码里用一个map去存各字符最近出现位置的下一个位置,好处是滑动窗口的左边缘i不用再一步步地挪了,直接一步到位

public class Solution {

public int lengthOfLongestSubstring(String s) {

int n = s.length(), ans = 0;

Map map = new HashMap<>();

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;

}

}

举个栗子

s="pwkpwo"

(1)最初,map为空,i=j=0,ans=窗口大小=j-i+1=1,更新map,记录'p'最近出现位置的下一个位置为:1

(2)i=0,j=1,窗口内无重复字符,ans=窗口大小=2,记录'w'最近出现位置的下一个位置为:2

(3))i=0,j=2,窗口内无重复字符,ans=窗口大小=3,记录'k'最近出现位置的下一个位置为:3

(4))i=0,j=3,s[j]与先前窗口内字符重复,因此需要将窗口左端点移动到让窗口不含'p'的最小位置(即map.get('p')),更新后i=1,这样s[i]到s[j]间又没有重复字符串了;同时更新'p'最近出现位置的下一个位置为:4

更新i后:

后边就不再解释了

总之这种方法的改进就是在窗口内字符与s[j]重复时,把窗口左端点一步一步挪动改进成了一步到位,但是本质上复杂度还是没有改变,依旧是O(n)

查找最长子串的长度(不重复字符) - linghu_java - 博客园​www.cnblogs.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值