0
点赞
收藏
分享

微信扫一扫

chapter04-字符串

点亮自己的那盏灯 2022-02-25 阅读 18

文章目录

一、滑动窗口系列

tip: 滑动窗口,可以借队列,双指针呈现。数组,字符串,链表这些线性结构容易考察,解法比较巧妙。窗口内的数需要满足哪些条件?重点,窗口左右边界移动的条件
https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/hua-dong-chuang-kou-by-powcai/
//下面是相关题目

//3. 无重复字符的最长子串
//线性结构,字串问题,考虑滑动窗口,双指针
    //Map用来干嘛?去重,题目要求不重复子串
    //Map k是字符串中的某位字符 v是该字符在索引中的位置
    //确定左右窗口移动的条件。
    //左窗口,若当前字符已存在于哈希表,左窗口移动到原位置的下一个
    //右窗口,不断向后移动(遍历序列的指针)
//关键代码,左窗口移动条件
public int lengthOfLongestSubstring(String s) {
        if(s == null || s.length() == 0) return 0;
        HashMap<Character,Integer> map = new HashMap<>();
        int left=0,maxLen=0;
        for(int i=0;i<s.length();i++){
            char ch = s.charAt(i);
            if(map.containsKey(ch)){
                left = Math.max(left,map.get(ch)+1);//重点,左窗口移动条件
            }
            map.put(ch,i);
            if(i-left+1 > maxLen){
                maxLen = i-left+1;
            }

        }
        return maxLen;
    }

//30. 串联所有单词的子串

//76. 最小覆盖子串
public String minWindow(String s, String t) {
        if(t == null || t.length() == 0) return "";
        int[] need = new int[128];
        for(int i=0;i<t.length();i++){
            char ch = t.charAt(i);
            need[ch]++;
        }
        //若need[i]为0,说明该窗口i元素刚好满足
        //若need[i]为负数,说明该窗口i元素已经超标,可移除

        int left=0,count=t.length(),start=0;
        int min = Integer.MAX_VALUE;
        for(int i=0;i<s.length();i++){
            char ch = s.charAt(i);
            if(need[ch] > 0){
                count--;
            }
            need[ch]--;


            if(count == 0){//窗口满足条件
                //当前窗口所满足的最小串
                while(left<i && need[s.charAt(left)] < 0){//左窗口移动条件
                    need[s.charAt(left)]++;//每窗口变化,一定要更新相对的条件表
                    left++;
                }

                //在满足最小串的前提下,更新
                if(i-left+1 < min){
                    start=left;
                    min=i-left+1;
                }

                //注意,再次移动左窗口,当前窗口不在满足条件
                need[s.charAt(left)]++;//每窗口变化,一定要更新相对的条件表
                left++;
                count++;//窗口不满足,count也要修改
            }
        }
        return min == Integer.MAX_VALUE ? "" : s.substring(start,start+min);
    }

//159. 至多包含两个不同字符的最长子串

//209. 长度最小的子数组

//239. 滑动窗口最大值
//为当前窗口维护一个单调递减队列

//维护一个单调递减队列,窗口变化(左右边界的变化),单调队列就更新
//左窗口移动,单调队列出队:
//	若队首元素是窗口左边界内的值,就不操作;否则,删除单调队列的队首
//右窗口移动,单调队列入队:
//	若插入的新值大于队尾元素,则删除队尾元素,直到队尾不再比新值小,新值入队列
public int[] maxSlidingWindow(int[] nums, int k) {
        int[] res = new int[nums.length-k+1];
        Deque<Integer> que = new ArrayDeque<>();
        int idx=0;
        for(int i=0;i<nums.length;i++){
            int left = i-k+1;//左边界下标
            
            //左边界
            while(!que.isEmpty() && left > que.peek()){
                que.poll();
            }
            //右边界
            while(!que.isEmpty() && nums[i] > nums[que.peekLast()]){
                que.pollLast();
            }
            
            que.offer(i);

            if(left >= 0){
                res[idx++]=nums[que.peek()];
            }
            
        }
        return res;
    }

//567. 字符串的排列

//632. 最小区间

//727. 最小窗口子序列

二、双子针

415. 字符串相加

demo:
输入:num1 = “11”, num2 = “123”
输出:"134"

tip:双指针,重点在,当前位,进位carry,两个变量。

public String addStrings(String num1, String num2) {
        String str = "";
        int n1=num1.length()-1,n2=num2.length()-1,carry=0;
        //指针放在字符串末尾n1,n2
		//注意遍历终止条件,n1>=0 || n2>=0 || carry!=0
        while(n1>=0 || n2>=0 || carry!=0){
            if(n1>=0) carry+=num1.charAt(n1--)-'0';
            if(n2>=0) carry+=num2.charAt(n2--)-'0';
            str = carry%10+str;//当前位
            carry /= 10;//进位
        }
        return str;
    }

三、栈与队列

20.有效括号

public boolean isValid(String s) {
        Deque<Character> stack = new ArrayDeque<>();
        for(int i=0;i<s.length();i++){
            char ch = s.charAt(i);
            if(ch == '('){
                stack.push(')');
            }else if(ch ==  '{'){
                stack.push('}');
            }else if(ch == '['){
                stack.push(']');
            }else if(!stack.isEmpty() && ch == stack.peek()){
                stack.pop();
            }else{
                return false;
            }
        }
        return stack.isEmpty();
    }

四、动态规划

5.最长回文串

	解法1,动态规划
    public String longestPalindrome(String s) {
        //dp[i][j] i是左边界,j是右边界,dp[i][j]表示该区间的子串是否为回文串
        //dp[i][j]=dp[i+1][j-1]
        int max=0;
        int left=0;
        boolean[][] dp = new boolean[s.length()][s.length()];
        for(int i=s.length()-1;i>=0;i--){
            for(int j=i;j<s.length();j++){
                if(s.charAt(i) == s.charAt(j)){
                    if(j-i<=1){
                        dp[i][j]=true;
                    }else if(dp[i+1][j-1]){
                        dp[i][j]=true;
                    }

					if(dp[i][j] && j-i+1>max){
	                    max = j-i+1;
	                    left = i;
                	}
                }
            }
        }

        return s.substring(left,left+max);
    }

解法2,中心扩散,双指针
int start=0,max=0;
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        for (int i = 0; i < s.length(); i++) {
            extend(s, i, i, s.length()); // 以i为中心
            extend(s, i, i + 1, s.length()); // 以i和i+1为中心
        }
        return s.substring(start,start+max);
    }

    void extend(String s, int i, int j, int n) {
        while (i >= 0 && j < n && s.charAt(i) == s.charAt(j)) {
            if(j-i+1 > max){
                max = j-i+1;
                start=i;
            }
            i--;
            j++;

        }
    }

647.回文子串

举报

相关推荐

0 条评论