Leetcode每日刷题:(滑动窗口+单调栈)&(字符串+数组+栈)

1.滑动窗口算法:最小覆盖子串

在这里插入图片描述

class Solution {
    public String minWindow(String s, String t) {
        //使用滑动窗口算法
        //base case
        if(s==null || s.length()==0){
            return "";
        }
        //使用needs记录target字符串中的字符以及个数
        Map<Character,Integer> needs=new HashMap<>();
        for(char ch:t.toCharArray()){
            needs.put(ch,needs.getOrDefault(ch,0)+1);
        }
        //定义一个window,用于后面记录窗口
        Map<Character,Integer> window=new HashMap<>();
        //使用双指针用于窗口的滑动,定义两个指针
        int left=0,right=0;
        //定义最小长度值minLen,用于比较得到最小长度子串
        int minLen=Integer.MAX_VALUE;
        //定义start,用于记录最小子串的开始位置
        int start=-1;
        //定义一个变量valid,记录已经满足要求的有效字符的个数
        int valid=0;

        //开始滑动窗口
        while(right<s.length()){
            char c=s.charAt(right);
            right++;
            if(needs.containsKey(c)){
                window.put(c,window.getOrDefault(c,0)+1);
                if(needs.get(c).equals(window.get(c))){
                    valid++;
                }
            }
            //将窗口中包含target中所有字符时,进行窗口收缩
            while(valid==needs.size()){
                if((right-left)<minLen){
                    start=left;
                    minLen=right-left;
                }
                //缩小窗口
                char d=s.charAt(left);
                left++;
                if(needs.containsKey(d)){
                    if(needs.get(d).equals(window.get(d))){
                        valid--;
                    }
                    window.put(d,window.getOrDefault(d,0)-1);
                }
            }
        }
        //最后返回最小子串
        return minLen==Integer.MAX_VALUE?"":s.substring(start,start+minLen);
    }
}

2.滑动窗口算法:字符串的排列

在这里插入图片描述

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        //使用滑动窗口
        //使用needs记录s2中字符以及个数
        Map<Character,Integer> needs=new HashMap<>();
        for(char ch:s1.toCharArray()){
            needs.put(ch,needs.getOrDefault(ch,0)+1);
        }
        //使用window记录窗口中字符以及个数
        Map<Character,Integer> window=new HashMap<>();
        //定义双指针
        int left=0,right=0;
        //有效字符个数
        int valid=0;

        //开始滑动窗口
        while(right<s2.length()){
            char c=s2.charAt(right);
            right++;
            if(needs.containsKey(c)){
                window.put(c,window.getOrDefault(c,0)+1);
                if(needs.get(c).equals(window.get(c))){
                    valid++;
                }
            }

            while(valid==needs.size()){
                if((right-left)==s1.length()){//当有效字符数和子串长度这两个条件都满足时,可以确定是子串的排列
                    return true;
                }
                char d=s2.charAt(left);
                left++;
                if(needs.containsKey(d)){
                    if(needs.get(d).equals(window.get(d))){
                        valid--;
                    }
                    window.put(d,window.getOrDefault(d,0)-1);
                }
            }
        }

        return false;
    }
}

3.滑动窗口算法:找到字符串中所有字母异位词

在这里插入图片描述

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        //使用滑动窗口
        List<Integer> res=new ArrayList<>();

        Map<Character,Integer> needs=new HashMap<>();
        for(char ch:p.toCharArray()){
            needs.put(ch,needs.getOrDefault(ch,0)+1);
        }

        Map<Character,Integer> window=new HashMap<>();

        int left=0,right=0;

        int valid=0;
        
        while(right<s.length()){
            char c=s.charAt(right);
            right++;
            if(needs.containsKey(c)){
                window.put(c,window.getOrDefault(c,0)+1);
                if(needs.get(c).equals(window.get(c))){
                    valid++;
                }
            }

            while(valid==needs.size()){
                if((right-left)==p.length()){
                    res.add(left);
                }
                char d=s.charAt(left);
                left++;
                if(needs.containsKey(d)){
                    if(needs.get(d).equals(window.get(d))){
                        valid--;
                    }
                    window.put(d,window.getOrDefault(d,0)-1);
                }
            }
        }

        return res;
    }
}

4.滑动窗口算法:无重复字符的最长子串

在这里插入图片描述

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.length()==0) return 0;
        //滑动窗口,当遇到重复字符时,右移left
        int maxLen=Integer.MIN_VALUE;
        int left=0,right=0;
        Map<Character,Integer> window=new HashMap<>();

        while(right<s.length()){
            char c=s.charAt(right);
            right++;
            window.put(c,window.getOrDefault(c,0)+1);
            //当窗口中元素出现重复时,开始收缩左窗口
            while(window.get(c)>1){
                char d=s.charAt(left);
                left++;
                window.put(d,window.getOrDefault(d,0)-1);
            }
            //更新放到外面,因为要等左边界收缩完事之后再计算窗口长度
            maxLen=Math.max(maxLen,right-left);
        }
        return maxLen;
    }
}

5.数组操作:O(1)时间插入、删除和获取元素

在这里插入图片描述

class RandomizedSet {
    private HashMap<Integer,Integer> map;//存储值到索引的映射
    private ArrayList<Integer> list;//存储值
    private Random rand;//产生随机数

    /** Initialize your data structure here. */
    public RandomizedSet() {
        map=new HashMap<>();
        list=new ArrayList<>();
        rand=new Random();
    }
    
    /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
    public boolean insert(int val) {
        if(!map.containsKey(val)){
            map.put(val,list.size());
            list.add(val);
            return true;
        }else{
            return false;
        }
    }
    
    /** Removes a value from the set. Returns true if the set contained the specified element. */
    public boolean remove(int val) {
        //首先找到val的位置,然后和末尾元素进行交换,交换之后再删除,这样时间复杂度就是O(1)
        if(map.containsKey(val)){
            //拿到val的索引
            int index=map.get(val);
            //交换
            int temp=list.get(list.size()-1);
            list.set(list.size()-1,val);
            list.set(index,temp);
            //删除末尾元素
            list.remove(list.get(list.size()-1));
            //别忘记map的操作!!!!
            map.put(temp,index);
            map.remove(val);
            return true;
        }else{
            return false;
        }
    }
    
    /** Get a random element from the set. */
    public int getRandom() {
        return list.get(rand.nextInt(list.size()));
    }
}

/**
 * Your RandomizedSet object will be instantiated and called as such:
 * RandomizedSet obj = new RandomizedSet();
 * boolean param_1 = obj.insert(val);
 * boolean param_2 = obj.remove(val);
 * int param_3 = obj.getRandom();
 */

6.数组操作:黑名单中的随机数

是通过将黑名单对应位置的元素换为末尾元素,然后减小原数组长度,最后随机返回的数值就不包含黑名单中的数。
在这里插入图片描述

class Solution {
    int sz;//去除黑名单之后的数组长度
    Map<Integer,Integer> mapping;
    Random rand;
    public Solution(int N, int[] blacklist) {
        sz=N-blacklist.length;
        mapping=new HashMap<>();
        rand=new Random();

        //先存放一个初始值,为了后面进行操作
        for(int b:blacklist){
            mapping.put(b,666);
        }

        int last=N-1;

        for(int b:blacklist){
            if(sz<=b) continue;
            while(mapping.containsKey(last)){
                last--;
            }
            mapping.put(b,last);//就是把该位置上的黑名单的值换成末尾的值
            last--;
        }
    }
    
    public int pick() {
        int index=rand.nextInt(sz);
        //如果mapping中含有该索引,说明该位置的值被换了,所以应该返回mapping中的值
        if(mapping.containsKey(index)){
            return mapping.get(index);
        }else{
            return index;
        }
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(N, blacklist);
 * int param_1 = obj.pick();
 */

7.单调栈:去除重复字母

在这里插入图片描述

class Solution {
    public String removeDuplicateLetters(String s) {
        //目标:(1)去重(2)保持相对顺序(3)字典序最小
        //单调栈思想
        Deque<Character> stack=new LinkedList<>();
        boolean[] instack=new boolean[256];//256是ASCII字符个数

        int[] count=new int[256];//记录字符个数
        for(char c:s.toCharArray()){
            count[c]++;
        }

        for(char c:s.toCharArray()){
            count[c]--;//遍历一个字符,就把这个元素的个数减1
            if(instack[c]) continue;
            //当待添加元素小于栈顶元素时
            while(!stack.isEmpty() && stack.peek()>c){
                if(count[stack.peek()]==0) break;//后面没有这个字符了,就不能pop出去
                instack[stack.pop()]=false;
            }
            stack.push(c);
            instack[c]=true;
        }
        StringBuilder sb=new StringBuilder();
        while(!stack.isEmpty()){
            sb.append(stack.pop());
        }
        return sb.reverse().toString();//由于出栈顺序使反的,所以需要reverse一下
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值