【算法】笔记:LeetCode 3. 无重复字符的最长子串

前言

今天写了一道题 LeetCode 3. 无重复字符的最长子串,思路还是不难的。初始版本自己写的,看了别人的答案觉得自己写的太丑了。于是乎,借鉴《重构》的思想(LeetCode 提供测试用例和运行,保障重构安全,真是太好了),把自己的版本重构下,记录下过程。

初始版本

	public int lengthOfLongestSubstring(String s) {
        char[] arr = s.toCharArray();

        int max = 0;
        int slow = 0;
        int fast = 0;
        
        Set<Character> set = new HashSet<>();

        // 根据fast重置slow节点
        while (slow < arr.length) {
            if (! set.contains(arr[fast])) {
                set.add(arr[fast]);
                max = Math.max(max, set.size());
                fast++;
                if (fast == arr.length) {
                    return max;
                }
            } else {
                max = Math.max(max, set.size());
                set.clear();
                slow++;
                // 从slow的起点开始重新寻找
                fast = slow;
            }
        }

        return max;
    }

优化遍历次数

摘一个 LeetCode网友的评论

每次左指针右移一位,移除set的一个字符,这一步会导致很多无用的循环。while循环发现的重复字符不一定就是Set最早添加那个,还要好多次循环才能到达,这些都是无效循环,不如直接用map记下每个字符的索引,直接进行跳转

public int lengthOfLongestSubstring(String s) {
        char[] arr = s.toCharArray();

        int max = 0;
        int slow = 0;
        int fast = 0;

        // 记录某个字符最接近队尾的标记,用于优化循环次数
        HashMap<Character, Integer> map = new HashMap<>();

        while (slow < arr.length) {
            if (! map.containsKey(arr[fast])) {
                map.put(arr[fast], fast + 1);
                
                max = Math.max(max, map.size());
                // 继续向后探索是否有更多不重字符
                fast++;
                
                // 越界处理
                if (fast == arr.length) {
                    return max;
                }
            } else {
                max = Math.max(max, map.size());
                slow = map.get(arr[fast]);
                fast = slow;
                map.clear();
            }
        }

        return max;
    }

优化代码结构

public int lengthOfLongestSubstring(String s) {
        char[] arr = s.toCharArray();

        int max = 0;
        int slow = 0;
        int fast = 0;

        // 记录某个字符最接近队尾的标记,用于优化循环次数
        HashMap<Character, Integer> map = new HashMap<>();

        while (slow < arr.length) {
            if (! map.containsKey(arr[fast])) {
                map.put(arr[fast], fast + 1);
                
                max = Math.max(max, map.size());
                // 继续向后探索是否有更多不重字符
                fast++;
                
                // 越界处理
                if (fast == arr.length) {
                    return max;
                }
            } else {
                max = Math.max(max, map.size());
                slow = map.get(arr[fast]);
                fast = slow;
                map.clear();
            }
        }

        return max;
    }

调整代码结构 - 分支结构重复的提到外层

public int lengthOfLongestSubstring(String s) {
        char[] arr = s.toCharArray();

        int max = 0;
        int slow = 0;
        int fast = 0;

		// 记录某个字符最接近队尾的标记,用于优化循环次数
        HashMap<Character, Integer> map = new HashMap<>();

        while (slow < arr.length) {
            if (! map.containsKey(arr[fast])) {
                map.put(arr[fast], fast + 1);
                // 继续向后探索是否有更多不重字符
                fast++;
            } else {
                slow = map.get(arr[fast]);
                fast = slow;
                map.clear();
            }
            
            max = Math.max(max, map.size());

            // 越界处理
            if (fast == arr.length) {
                return max;
            }
        }

        return max;
    }

调整代码结构 – 内存优化、循环条件

   public int lengthOfLongestSubstring(String s) {
        char[] arr = s.toCharArray();

        int max = 0;
        int slow = 0;
        int fast = 0;
		
		// 记录某个字符最接近队尾的标记,用于优化循环次数
        HashMap<Character, Integer> map = new HashMap<>();

		// 越界条件移到while上
        while (slow < arr.length && fast < arr.length) {
            if (! map.containsKey(arr[fast])) {
                map.put(arr[fast], fast + 1);
                // 继续向后探索是否有更多不重字符
                fast++;
            } else {
                slow = map.get(arr[fast]);
                fast = slow;
                // 用 new 表达一个全新的map
                map = new HashMap<>();
            }
            
            max = Math.max(max, map.size());
        }

        return max;
    }

调整代码结构 – 反转 ! xxx 条件

   public int lengthOfLongestSubstring(String s) {
        char[] arr = s.toCharArray();

        int max = 0;
        int slow = 0;
        int fast = 0;

        HashMap<Character, Integer> map = new HashMap<>();

        while (slow < arr.length && fast < arr.length) {
            if (map.containsKey(arr[fast])) {
                slow = map.get(arr[fast]);
                fast = slow;
                map = new HashMap<>();
            } else {
				map.put(arr[fast], fast + 1);
                fast++;
            }
            
            max = Math.max(max, map.size());
        }

        return max;
    }

后记

时常提醒自己,写算法题的时候,不要急功近利。通过迭代答案,自己的答案也会变得简洁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值