代码优化思路 | 青训营

111 阅读2分钟

题目

演示例题为leetcode题目中一道经典题目

Longest Substring Without Repeating Characters

即在一个字符串中寻找最大不重复子串 已有针对Java例题,使用go语言实现,并进行优化

例如:

Input: "abcabcbb"
Output: 3

Input: "bbbbb"
Output: 1

Input: "pwwkew"
Output: 3

方法一:Java举例方法:穷举

暴力法,逐步检查所有的子字符串,找到最大不重复子字符串
时间复杂度:O(n^3)
空间复杂度:O(min(m,n)), 需要O(K)的空间,其中K表示set的大小,取决于字符串n的大小以及字符集/字母m的大小。

public static int lengthOfLongestSubstring1(String s) {
 int n = s.length();
 int ans = 0;
 String maxson = null;

 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);
             if (j - i > ans) {
                 ans = j - i;
                 maxson = s.substring(i, j);
             }
         }
     }
 }
 System.out.println(maxson);
 return ans;
}

public static boolean allUnique(String s, int start, int end) {
 Set<Character> set = new HashSet<>();
 for (int i = start; i < end; i++) {
     Character c = s.charAt(i);
     if (set.contains(c)) {
         return false;
     }
     set.add(c);
 }
return true;
}

不论是在时间复杂度上,还是空间复杂度上,穷举都过于浪费资源,由此引出第二种方法

方法二 使用go语言解决

时间复杂度:O(2n) = O(n),在最糟糕的情况下首尾都访问了n次 。
空间复杂度:O(min(m,n)),滑动窗口需要O(K)的空间,其中K表示set的大小, 取决于字符串n的大小以及字符集/字母m的大小。

func lengthOfLongestSubstring2(s string) int {
    if len(s) == 0 {
       return 0
    }
    var freq [127]int
    result, left, right := 0, 0, -1

    for left < len(s) {
       if right+1 < len(s) && freq[s[right+1]] == 0 {
          freq[s[right+1]]++
          right++

       } else {
          freq[s[left]]--
          left++
       }
       result = max(result, right-left+1)
    }
    return result
}

代码分析

  1. 滑动窗口先判断输入的字符串长度不为
  2. 滑动窗口左侧为left,右侧为right
  3. 逐个接收字符,并判断
    1)窗口右侧是否溢出
    2)传入元素是否已经在freq内
  4. 如果传入的元素不在freq中出现过,则标记出现,即将freq对应的元素置为1
  5. 如果传入的字符在freq中已经存在,则证明最左侧就是重复元素
  6. 窗口接收元素,同时删除最左侧元素
  7. 使用result接收 当前窗口与result 中的最大值
  8. 回到第二步继续判断,直到遍历字符串中的每一个元素
  9. 输出result

心得体会

解题步骤
第一步 应该将问题拆解成片段
第二步 将片段由代码实现
第三步 扩充片段,解决问题 第四步 优化代码,寻找更优解
对于枚举能够解决的问题,首先应该将问题使用枚举实现,再优化
对于任意代码,时间复杂度与空间复杂度往往不可兼得,在运行时可以优先降低其中一个,然后再去寻找更优解