龙空技术网

Leetcode最大子串和、最小子串覆盖、 最长子串不重复问题

Counting2stars 287

前言:

现在我们对“java中等号和equals”大约比较看重,大家都想要了解一些“java中等号和equals”的相关文章。那么小编同时在网络上网罗了一些关于“java中等号和equals””的相关内容,希望兄弟们能喜欢,大家一起来学习一下吧!

目录

最大子串和问题(简单)

题目

思路一

思路二

最小子串覆盖问题(困难)

题目

思路一

思路二

最长子串不重复问题(中等)

题目

思路一

思路二

最大子串和问题(简单)

题目

给定一个整数数组,求出数组中连续的最大的子串和。

例如: 2, -1, 3, 5, 6, -3

最大子串和为: 2-1+3+5+6=15

思路一

采用暴力循环的方式,找出每趟最大的子串和,然后再比较每趟的值,最大的那个值即为最大子串和。

完整代码:

   private static Integer findMaxSumStrOne(int[] arr) {        int max = arr[0];        for (int i = 0; i < arr.length; i++) {            int temp = arr[i];            int iMax = temp;            for (int j = i + 1; j < arr.length; j++) {                int current = temp + arr[j];                if (current > iMax) {                    iMax = current;                }                temp = current;            }            if (iMax > max) {                max = iMax;            }        }        return max;    }

此方法虽然能求解,但是时间复杂度为0(n2), 效率比较低。

思路二

采用淘汰的思想,每次只加对当前贡献大的数。

class Solution {   public Integer maxSubArray(int[] arr) {       int ans=arr[0];       int pre=0;       for(int i=0;i<arr.length;i++){           pre=Math.max(arr[i],pre+arr[i]);           ans=Math.max(ans,pre);       }       return ans;    }}

最小子串覆盖问题(困难)题目

给定一个字符串S,字符串T, 求字符串S包含字符串T的最短子串。

例如: S="ADOBECODEBANC", T="ABC"

输出结果: "BANC"

思路一

使用暴力破解的方法

采用顺序字符串的格式获取源字符串的子串,然后用源字符串的子串对目标字符串进行逐个匹配,命中一个字符将目标字符串把该字符给剔除掉,直到目标字符串里的字符全部剔除完毕,就表示找到合适的字符串。

每次找到符合要求的子串(Target)时,比较foundStr和符合要求的Target串的长度,如果长度比源串长度小,就把目标串赋值给foundStr,最终返回结果即可。

也可以根据下标的差值来比较,取差值最小的那个即可。

   private static String findStr(String s, String t) {        if (s.length() < t.length()) {            return "";        }        if (t.length() == 1 && s.contains(t)) {            return t;        }        String foundStr = "";        for (int i = 0; i < s.length(); i++) {            String source = s.charAt(i) + "";            String target = t;            int index = t.indexOf(source);            if (index != -1) {                target = target.substring(0, index) + target.substring(index + 1);                // 目标的子串包含了一个才进行匹配                for (int j = i + 1; j < s.length(); j++) {                    String sub = s.charAt(j) + "";                    // subStr字符串中的所有字符必须全部命中                    int subIndex = target.indexOf(sub);                    if (subIndex != -1) {                        target = target.substring(0, subIndex) + target.substring(subIndex + 1);                        if (target.length() == 0) {                            System.out.println("符合要求:(" + i + "," + j + ")");                            String str = s.substring(i, j + 1);                            if ("".equals(foundStr)) {                                foundStr = str;                            } else {                                foundStr = str.length() <= foundStr.length() ? str : foundStr;                            }                        }                    }                }            }        }        return foundStr;    }

打印结果:

输入: S= "CQDBANC", T="ABC"

输出: BANC

此方法虽然可行,但是时间复杂度是o(n2), 效率比较低,在leetcode里执行会出现超时的情况。

思路二

方法二,采用滑动窗口思想

1) 先将子串的所有字符放到hashMap里,key为字符,value为字符的个数。

2) 然后在主串里设置2个游标,都从左边开始移动,先移动右指针,找到符合条件的子串后,再去移动左指针。

3) j每次找到符合子串的字符(采用map的containsKey()方法来判断),找到符合的count 加1,count初始值为0, 然后hashmap里key对应的value值也-1。同样的i也会向右移动,如果i找到符合的字符在hashmap里,并且hasmap.get(key)==0的情况下,count需要减1,因为map的key对应的value值为0表示j已经找到了符合要求的同样字符,因此count-1。

循环直到count值等于子串的长度值,即找到了覆盖目标子串的字符串。每找到一次与len做比较,取最终长度最小的字符串即可。

滑动窗口思想如下:

此处需要注意的地方:

1) 对于left来讲, 先right++ 然后再判断 , 因为后面的字符我们是不知道的。

2) 对于left来讲,先判断left对应的字符是否满足条件,如果发现left正好命中到了字符串subStr的一个字符,并且right命中过该字符全部的次数(开始时subStr的字符个数),那么需要count--,然后再left++。

class Solution {    public String minWindow(String s, String t) {        // 用hashmap存放子串字符出现的个数        HashMap<Character, Integer> hashMap = new HashMap<>();        for (int i = 0; i < t.length(); i++) {            if (hashMap.containsKey(t.charAt(i))) {                hashMap.put(t.charAt(i), hashMap.get(t.charAt(i)) + 1);            } else {                hashMap.put(t.charAt(i), 1);            }        }        int left = 0;        int right = -1;        //[left,right] s中包含t字符的出现的次数        int count = 0;        String result = "";        int len = s.length() + 1;        while (left < s.length()) {            if (right + 1 < s.length() && count < t.length()) {                // 滑动右边窗口                right++;                Character rightChar=s.charAt(right);                if (hashMap.containsKey(rightChar)) {                    if (hashMap.get(rightChar) > 0) {                        count++;                    }                    // 如果正好包含右边的字符,那么就将字符出现的次数-1                    hashMap.put(rightChar, hashMap.get(rightChar) - 1);                }            } else {                // count 表示出现t中字符的次数,如果刚好为2,记录满足的结果后,那么就需要移动左指针继续寻找符合条件的最小子串。                // 否则滑动左边窗口                Character leftChar=s.charAt(left);                if (hashMap.containsKey(leftChar)) {                    // 当map中的次数为0时,t中的字符出现的次数-1。                    if (hashMap.get(leftChar) == 0) {                        count--;                    }                    // 每滑动左边窗口,map中的出现的字符+1                    hashMap.put(leftChar, hashMap.get(leftChar) + 1);                }                left++;            }            if (count == t.length()) {                if (right - left + 1 < len) {                    len = right - left + 1;                    result = s.substring(left, right + 1);                }            }        }        return result;    }        }

此算法的时间复杂度为: o(n), 空间复杂度为o(m), m为子串的长度。

最长子串不重复问题(中等)题目

给定一个字符串,找出字符串中最长的不重复的子串,并返回它的长度。

思路一

使用暴力循环破解的方式,通过两次循环,每次取出子串进行判断子串是否是不重复的,然后不断的比较之前的不重复的子串长度,最后返回。

此方式的时间复杂度是大于o(n2), 耗时比较久,不可取。

思路二

滑动窗口思想。

1) 定义左指针和右指针,左指针和右指针之间的窗口为滑动窗口。

2) 右指针每移动一位时,将不重复的字符添加到 Set集合里,Set集合用来判断是否出现重复字符。

3) 当右指针开始遇到重复的字符时,那么计算一次长度,同时左指针右移动一位。

4) 如果左指针移动一位后,右指针的下一位仍然重复,那么在右指针的位置再计算一次长度,同时左指针向右移动一位。

package leetcode100;import java.util.HashSet;import java.util.Set;/** * @decription: * @date: 2021/7/20 17:29 * 给定⼀个字符串,找到没有重复字符的最⻓⼦串,返回它的⻓度。 */public class MaxNotRepeatStrProblem {    public static void main(String[] args) {        String str = "asjfpoajfeskahfiasfjoj";        Integer length = findMaxLengthNotRepeatStr(str);        System.out.println("长度为:" + length);    }    /**     * 实现思路: 每次取出来字符串并判断不重复后,后续判断只需要判断最后一个字符不在之前的字符串里即可,否则滑动窗口。     *  将已有的字符串存在hash里,hash的判断时间复杂度为o(1), 那么总的时间复杂度为o(n)。     * @param str     * @return     */    private static Integer findMaxLengthNotRepeatStr(String s) {        int len=s.length();        int ans=0;        int right=-1;        Set<Character> set=new HashSet<>();        for(int i=0;i<len;i++){             if(i!=0){                set.remove(s.charAt(i-1));            }           while(right+1<len && ! set.contains(s.charAt(right+1))){                set.add(s.charAt(right+1));                   right++;            }            ans=Math.max(ans,right-i+1);        }        return ans;    }}

提交结果:

标签: #java中等号和equals