给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
经过一次线上笔试,发现自己直接写代码的能力严重不足,所以这次就先在网页上编写代码,不借助eclipse工具,慢慢练习
然后就从每次的错误开始说起吧。
try1
发现自己挺多小毛病的String的charAt方法写成CharAt,然后长度就直接是 s.length ,实际上是 s.length()
class Solution {
public static int lengthOfLongestSubstring(String s) {
int cout = 0;
int temp = 0;
int i = 0;
int j = 0;
for(i = 0;i<s.length();i++){
for(j = i+1;j<s.length();j++){
if(s.charAt(i)!=s.charAt(j)){
cout++;
continue;
}else{
temp = cout>temp?cout:temp;
cout = 0;
break;
}
}
if(j == s.length()){
temp = cout>temp?cout:temp;
break;
}
}
return temp;
}
}
这是一开始流程图都没画直接写的,想法是第i个字符与后面第j(j自增)个字符逐个比较。后来一想,很明显错了,因为假设第一个字符和第一二三四五个字符比较,第一个字符和第六个字符相同,但是中间的字符却没有相互比较,如果第二三个字符相同,就断了,所以错了。
try2
所以就开始画流程图啦,想想,应该要有三个循环,开始字符的循环一个,然后最后字符循环一个,然后中间字符循环一个。
class Solution {
public int lengthOfLongestSubstring(String s) {
int cout = 0;
int temp = 0;
int i = 0;
int j = 0;
int k = 0;
// for(i = 0;i<s.length();i++)
while(i<s.length()){
for(j = i+1;j<s.length();j++){
k = i;
if(s.charAt(i)!=s.charAt(j)){
while(k != j-1){
k++;
if(s.charAt(k) != s.charAt(j)){
continue;
}
else{
cout =k-i;
temp = cout>temp?cout:temp;
i = k+1;
break;
}
}
/* if(k == j-1){
continue;
}
*/
}else{
cout = j-i;
temp = cout>temp?cout:temp;
i = j;
break;
}
}
if(j == s.length()){
break;
}
}
/* if(s.length() <= 1){
temp = s.length();
}
*/ return temp;
}
}
try(n)(right)
人生艰难啊,力扣的题做到心态爆炸,每一次以为成功了,结果又出了一个问题,最好靠着debug一点点分析,才终于做成。不多说,上代码
class Solution {
public int lengthOfLongestSubstring(String s) {
int cout = 0;
int temp = 0;
int i = 0;
int j = 0;
int k = 0;
// for(i = 0;i<s.length();i++)
while(i<s.length()){//开始字符
for(j = i+1;j<s.length();j++){//最后字符
k = i;
if(s.charAt(i)!=s.charAt(j)){//开始字符与最后字符比较
while(k != j-1){
k++;
if(s.charAt(k) != s.charAt(j)){//中间字符与最后字符比较
continue;
}
else{
cout =k-i+1;
temp = cout>temp?cout:temp;
int x = 0;
for(x = k+1;x<=j;x++){
if(s.charAt(k)!=s.charAt(x)){
//和最后字符相同的中间字符与中间字符、最后字符之间的字符比较
continue;
}
else{
cout = x-i;
temp = cout>temp?cout:temp;
}
}
i = k+1;
break;
}
}
// if(k == j-1) {
// continue;
// }
}else{
cout = j-i;
temp = cout>temp?cout:temp;
i++;
break;
}
}
if(j == s.length()){
cout = j-i;
temp = cout>temp?cout:temp;
i = j;
break;
}
}
return temp;
}
}
问题
因为中间尝试了很多,改了很多次代码,就不一一上代码了,主要说说碰到的问题
1.问题: 最外层while循环没有break,直接导致风扇疯狂转啊转,死循环,没得出来,
解决方法:加上个break的条件再break
2. 上面的流程图没法看,自己画的更丑,但毕竟辛辛苦苦画出来的,即使有点错,也放上去吧
3.问题: 一条字符串全是不同字符的情况,最后因为画的流程图里没有赋值,得出的结果居然是0
解决方法:就是最外层循环break的条件了,(j-i);
4. 问题:abcb型,只能得个2出来,因为(1)和(3)相同,直接就跳到k-i+1(这里算的是i到k之间的字符数),算完之后直接break了,没算后面的
解决方法:在break之前再加个循环,加个条件,用来比较第k个字符后第k个到第j字符间是否相同,比较得到的数减去一开始(i)的数,与temp比较,决定是否放入答案temp中
5. 问题:dvdf型,也是只能得出2个出来,原因是直接跳到i=j上了,没有把i逐个循环(好像这样的话也可以一开始就用for的i循环?)
解决方法:把第二层循环break前的i =j换成i++;
小结
做到心态炸,最后还是用debug一点一点的修正了答案,但是我的方法好像不太好,
时间复杂度和空间复杂度都挺差= =!虽然一开始画的图就能解决三个例题,但是不够全面,后来用了三四个小时才终于解决问题。
还是得认真学,多多的练哇。
题解
有点惭愧,学了那么久Java,还是停留在C语言的思想上,没有真正运用到Java的面向对象思想。应当注意
暴力法
- 要检查一个字符串是否有重复字符,我们可以使用集合。我们遍历字符串中的所有字符,并将它们逐个放入 set 中。在放置一个字符之前,我们检查该集合是否已经包含它。如果包含,我们会返回 false。循环结束后,我们返回 true。
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;
}
}
滑动窗口
意思就是先令i=j=0,然后开始 j 递增,直至有重复的出现(用Set的contains()方法),然后 递增 i,若还是重复,则窗口开始滑动。 如果一开始就遇到最长长度,那么 i 和 j同时递增【即窗口滑动】,直至j等于字符串长度。
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;
}
}
优化的滑动窗口
在滑动窗口基础上,检测到重复的字符的位置 j’,然后直接把i设置成 j’+1,而不用i递增。
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;
}
}