leetcode Longest Substring Without Repeating Characters 没有重复字符的最长子字符串

在做该题时,一开始思路是对的,但是写法不同,效率截然不同

// 第一个写法,提交时一个几十位的字符串,提示time limit exceeded,后来在本地运行了以下,效率5ms

private static int method1(String s) {

long start = System.currentTimeMillis();

if (s.equals("")) {

return 0;

}

int length = 1;

int i = 0;

while (i < s.length() - 1) {

for (int j = i + 1; j <= s.length() - 1; j++) {

System.out.println(i + "----" + j);

String sub = s.substring(i, j);

if (!sub.contains(String.valueOf(s.charAt(j)))) {

System.out.println(sub + "----" + s.charAt(j));

int l = j - i + 1;

if (l > length) {

length = l;

}

// 最后j到了s的末尾之后,i也可以结束了

if (j == s.length() - 1) {

i = s.length() - 1;

}

else {

i = j;

break;

}

}

}

long end = System.currentTimeMillis();

System.out.println("程序运行时间:" + (end - start) + "ms");

return length;

}

// 第二种写法,stringbuffer替代string,跟method1相比,超时的字符串,效率提升1ms,但是依然不够

private static int method2(String s) {

long start = System.currentTimeMillis();

if (s.equals("")) {

return 0;

}

int length = 1;

int i = 0;

StringBuffer sub = new StringBuffer("");

while (i < s.length() - 1) {

for (int j = i + 1; j <= s.length() - 1; j++) {

System.out.println(i + "----" + j);

sub.setLength(0);

sub = sub.append(s.substring(i, j));

if (!sub.toString().contains(String.valueOf(s.charAt(j)))) {

System.out.println(sub + "----" + s.charAt(j));

int l = j - i + 1;

if (l > length) {

length = l;

}

// 最后j到了s的末尾之后,i也可以结束了

if (j == s.length() - 1) {

i = s.length() - 1;

}

} else {

i = j;

break;

}

}

}

long end = System.currentTimeMillis();

System.out.println("程序运行时间:" + (end - start) + "ms");

return length;

}

//运用纯指针的写法,而不是依次遍历,效率提升非常明显,前两种方法超时的字符串,只需要0ms,但是,几百位的字符串,依然超时

private static int method3(String s) {

long start = System.currentTimeMillis();

if (s.equals("")) {

return 0;

}

int length = 1;

int i = 0;

int j = 1;

StringBuffer sub = new StringBuffer("");

while (i <= s.length() - 1 && j <= s.length() - 1) {

sub.setLength(0);

sub.append(s.substring(i, j));

if (sub.toString().contains(String.valueOf(s.charAt(j)))) {

if (j - i > length) {

length = j - i;

}

i = i + sub.toString().indexOf(s.charAt(j)) + 1;

j = i + 1;

} else {

if (j == s.length() - 1) {

if (j - i + 1 > length) {

length = j - i + 1;

}

break;

}

j++;

}

}

long end = System.currentTimeMillis();

System.out.println("程序运行时间:" + (end - start) + "ms");

return length;

}

做到此时已经是有点头大,所以百度了一下大众的写法,其中绝大部分都用到了hashmap来进行记录,想必是通过map来记录是否有重复,从而取代了我用来判断是否重复的方法 即string的contains方法,比如以下一位大神的写法

public int lengthOfLongestSubstring(String s) {
HashMap<character, integer=""> map = new HashMap<character, integer="">();
if (s == null || s.length() == 0) return 0;
if (s.length() == 1) return 1;
int rightPointer = 0, leftPointer = rightPointer - 1, answer = 0;
while (rightPointer != s.length()) {
Integer previousOccurrence = map.put(s.charAt(rightPointer), rightPointer);
if (previousOccurrence != null) {
leftPointer = Math.max(leftPointer, previousOccurrence);
}
answer = Math.max(answer, rightPointer - leftPointer);
rightPointer++;
}
return answer;
}

所以,自己转换了以下思路,写出了如下代码,accepted,如此可见java中Collection的重要性

public class Solution {
public int lengthOfLongestSubstring(String s) {
long start = System.currentTimeMillis();
if (s == null || s.equals("")) {
return 0;
}
Map<Character, Integer> map = new HashMap<Character, Integer>();
map.put(s.charAt(0), 0);
int length = 1;
int left = 0;
int right = 1;
while (right < s.length()) {
// System.out.println("left:"+left+"------right:" + right);
// 如果key存在了,那么put方法返回的是之前存入的值
Integer loc = map.put(s.charAt(right), right);
// System.out.println(map.get(s.charAt(right)));
if (loc != null) {// 说明left到right之间,包含了s.charAt(right),即该没有重复的字符串到此为止
// 判断
if (left <= loc) {
if (right - left > length) {
length = right - left;
}
left = loc + 1;
right ++;//假设right未加1前,值为n,字符为‘d’,right此处不能为left+1,因为当right的值之前存在过,left=loc+1后,left跟right之间肯定是没有重复字符的
//而且,当right=left+1,不仅有的字符又重新遍历了一遍,而且right相当于回退了,d的value已经是n,再重新遍历到d时,left一定是小于n的,实际上left比较的应该是再之前d对应的value,不应该出现这种情况,参考"dvdf"
}else{
right++;
}
} else {
right++;
}
}
if (right - left > length) {
length = right - left;
}
long end = System.currentTimeMillis();
System.out.println("程序运行时间:" + (end - start) + "ms");
return length;
}
}

实际上,在此方法中,一方面是特别注视的地方,此处有bug,查找了半天。另一方面,总是提示超时,后来发现是sysout的原因。

另外,里面的if写法还可以优化。

 

 

原文地址:https://www.cnblogs.com/govoid/p/4975592.html