zoukankan      html  css  js  c++  java
  • 【算法刷题】无重复字符的最长子串

    本文为个人解题思路整理,水平有限,有问题欢迎交流


    概览

    第一次解出来没花多长时间,但是提交后发现击败了30%的人,也就是意味着还有大幅度优化的空间,于是再优化了一下

    难度:中等

    核心知识点:滑动窗口 + 贪心


    题目来源

    力扣:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/


    题目内容

    给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度


    样例

    输入1

    pwwkew

    输出1

    3

    解释1

    最长无重复为wke


    解题思路

    明显这是一个滑动窗口问题,即一个长度为L的窗口从左往右滑动,找到符合情况的最大L,下面进行思路分析

    • 我们需要确定目标的长度,那么需要知道头head和尾tail,并确保中间的所有元素不重复

    • 对于一个子串,如果存在重复元素,那么包含这个子串的任何其他子串也存在重复元素

    • 贪心:即尽可能追求更多,若一个子串满足要求,那么考虑这个子串与相邻的字符能否组成更大的子串,进而将子串扩充,子串越大越好,因此得到的结果是对于每个起点,只有一个最远的终点,即每个起点对应最多一个结果

      比如子串p符合要求,那么考虑pw也符合要求,那么考虑pww不符合要求,则已p开头的最长子串是pw,不可继续贪心

    • 滑动:前面说了pww的最长子串是pw,那么对于pww****呢?*代表暂时未知的字符,如果后面的结果比pw长呢?那么我们也需要搜索后面的字符串,但是两个w不能重复,于是不得不放弃一个w

      • 放弃后一个的结果就是pw
      • 放弃前一个的结果是solve("w****")resolve表示解决方法

      也就是说 solve("pww****") = max(resolve("pw"), soleve("pw****"))

      在对soleve("pw****")同样的方法处理下去,即可拿到最终的最大值

      比如对于目标字符串abcadefa,处理步骤如下(偷个懒,resolve省掉啦,不然看上去很乱)

      //第一次处理,两个a不同,必须放弃其中一个
      solve("abcdadfa")=max(solve("abcd"),solve("bcdadfa"));
      solve("abcd")=4;
      //第二次处理,两个d不同
      solve("bcdadfa")=max(solve("bcda"),solve("adfa"));
      solve("bcda")=4;
      //第三次处理,两个a不同
      solve("adfa")=max(solve("adf"),solve("dfa"));
      solve("adf")=3;
      solve("dfa")=3;
      //那么最终结果为4
      solve("abcdadfa")=max(4,max(4,max(3,3)))=max(4,4,3,3)=4
      

      即从左往右贪心出最长的不重复字符串,直到出现一个与已有字符重复的目标,就贪不动了

      这时候考虑放弃已有字符的和放弃新字符两种情况,取两种情况的结果最大的那个

      • 放弃新字符,即当前子串的长度就是结果,我们一直在保证没有重复字符嘛
      • 放弃旧字符,则从旧字符的下一位开始下一步检索,对新的目标重复贪心和处理

    解决方案

    1. 设置两个指针 left 和 right ,初识均指向字符串的头部,设置初始最大长度ans = 0

    2. 记录right目标的字符和位置,right 右移,直至其目标字符已出现过,开始处理

      1. 放弃新字符,则旧字符串的长度为 right-left,修改ans = max(ans, right - left)
      2. 放弃旧字符,若旧字符位置的oldPosition,则 left 修改为oldPosition + 1

      即得到新的字符串

    3. right 继续右移,重复第二步

    完整代码

    这里使用数组存储位置,而非map,因为字符可按ASCII码存储,显然一个int[128]是比map的效率更高

    package com.company;
    
    import java.util.*;
    
    /**
     * @title 无重复字符的最长子串
     * @description 力扣3
     * @author Echo_Ye
     * @date 2020/9/22 11:56
     * @email echo_yezi@qq.com
     */
    public class LengthOfLongestSubstring {
        public static void main(String[] args) {
            new LengthOfLongestSubstring();
        }
    
        public LengthOfLongestSubstring() {
            int ans = lengthOfLongestSubstring("abcdadfa");
            System.out.println(ans);
        }
    
        public int lengthOfLongestSubstring(String s) {
            int ans = 0;
            int left = 0, right = 0;
            int[] map = new int[128];
            Arrays.fill(map, -1);
            while (right <= s.length()) {
                if (right == s.length()) {
                    //结算,结束查找
                    ans = max(ans, right - left);
                    break;
                }
                //检查right目标
                if (left == right || map[s.charAt(right)] == -1 || map[s.charAt(right)] < left) {
                    //存储位置
                    map[s.charAt(right)] = right;
                    //指针重叠的时候,右指针右移1
                    //右指针目标未出现过的时候,右指针右移1
                    right++;
                } else {
                    //结算,left移至旧字符右1位置
                    ans = max(ans, right - left);
                    left = map[s.charAt(right)] + 1;
                }
            }
            return ans;
        }
    
        int max(int a, int b) {
            return a > b ? a : b;
        }
    }
    

    结果

    image-20200922115834734

    性能

    image-20200922115900594

    后记

    没有涉及什么高深的算法,就是思路灵活转换而已,好吧其实涉及到高级算法我可能就不会做了哈哈哈哈哈


    作者:Echo_Ye

    WX:Echo_YeZ

    Email :echo_yezi@qq.com

    个人站点:在搭了在搭了。。。(右键 - 新建文件夹)

  • 相关阅读:
    eclipse中包的位置
    404代码错误解决
    servlet-web.xml配置
    java web.xml配置servlet
    1031整理
    1030整理
    rownum
    存储过程和自定义函数的区别
    课堂整理
    练习
  • 原文地址:https://www.cnblogs.com/silent-bug/p/13711285.html
Copyright © 2011-2022 走看看