算法训练--MSTOP(1)

197 阅读11分钟

哈希表

3. 无重复字符的最长子串

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            if(s.length()==0) return 0;
            Map<Character,Integer> map=new HashMap<>();
            int left=0,max=Integer.MIN_VALUE;
            for(int right=0;right<s.length();right++){
                char cRight=s.charAt(right);
                map.put(cRight,map.getOrDefault(cRight,0)+1);
                while(map.get(cRight)>1){
                    //出现重复
                    char cLeft=s.charAt(left);
                    map.put(cLeft,map.get(cLeft)-1);
                    left++;
                }
                max=Math.max(max,right-left+1);
            }
            return max;
        }
    }
    

560. 和为 K 的子数组

  • 题目描述

    image.png

  • 题解

    为什么这题不可以用双指针/滑动窗口:因为nums[i]可以小于0,也就是说右指针i向后移1位不能保证区间会增大,左指针j向后移1位也不能保证区间和会减小。给定ji的位置没有二段性

    class Solution {
        public int subarraySum(int[] nums, int k) {
            //扫描一遍数组, 使用map记录出现同样的和的次数
            //对每个i计算累计和sum并判断map内是否有sum-k
            Map<Integer,Integer> map=new HashMap<>();
            map.put(0,1);
            int sum=0,res=0;
            for(int i=0;i<nums.length;i++){
                sum+=nums[i];
                if(map.containsKey(sum-k)){
                    res+=map.get(sum-k);
                }
                map.put(sum,map.getOrDefault(sum,0)+1);
            }
            return res;
        }
    }
    

1. 两数之和

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int[] twoSum(int[] nums, int target) {
            Map<Integer,Integer> map=new HashMap<>();
            for(int i=0;i<nums.length;i++){
                int temp=target-nums[i];
                if(map.containsKey(temp)){
                    return new int[]{map.get(temp),i};
                }
                map.put(nums[i],i);
            }
            return null;
        }
    }
    

138. 复制带随机指针的链表

  • 题目描述

    image.png

  • 题解

    class Solution {
        public Node copyRandomList(Node head) {
            if(head == null) return head;
            // map方法,空间复杂度O(n)
            Node node = head;
            // 使用hash表存储旧结点和新结点的映射
            Map<Node,Node> map = new HashMap<>();
            while(node != null){
                Node clone = new Node(node.val,null,null);
                map.put(node,clone);
                node = node.next;
            }
            node = head;
            while(node != null){
                map.get(node).next = map.get(node.next);
                map.get(node).random = map.get(node.random);
                node = node.next;
            }
            return map.get(head);
        }
    }
    

76. 最小覆盖子串

  • 题目描述

    image.png

  • 题解

    class Solution {
        public String minWindow(String s, String t) {
            if(s.length()==0) return "";
            if(t.length()>s.length()) return "";
            char[] sArr=s.toCharArray();
            char[] tArr=t.toCharArray();
            Map<Character,Integer> needMap=new HashMap<>();
            Map<Character,Integer> map=new HashMap<>();
            int left=0,maxNum=0,start=0,minLen=Integer.MAX_VALUE;
            for(char c:tArr){
                needMap.put(c,needMap.getOrDefault(c,0)+1);
            }
            for(int right=0;right<sArr.length;right++){
                char ch=sArr[right];
                map.put(ch,map.getOrDefault(ch,0)+1);
                if(map.get(ch).equals(needMap.get(ch))){
                    //满足条件的字符数
                    maxNum++;
                }
                //满足条件时缩小窗口
                while(needMap.size()==maxNum){
                    //记录当前窗口
                    if(right-left<minLen){
                        start=left;
                        minLen=right-left+1;
                    }
                    //缩小左边界
                    char cleft=sArr[left];
                    if(map.get(cleft).equals(needMap.get(cleft))){
                        maxNum--;
                    }
                    map.put(cleft,map.get(cleft)-1);
                    left++;
                }
            }
    		return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
        }
    }
    

347. 前 K 个高频元素

  • 题目描述

    ![image-20220905214401610](/Users/bin.wang/Library/Application Support/typora-user-images/image-20220905214401610.png)

  • 题解

    class Solution {
        public int[] topKFrequent(int[] nums, int k) {
            int[] res=new int[k];
            Map<Integer,Integer> map=new HashMap<>();
            for(int n:nums){
                map.put(n,map.getOrDefault(n,0)+1);
            }
            Set<Map.Entry<Integer,Integer>> set=map.entrySet();
            PriorityQueue<Map.Entry<Integer,Integer>> queue=new PriorityQueue<>((p1,p2)->p1.getValue()-p2.getValue());
            for(Map.Entry<Integer,Integer> entry:set){
                queue.offer(entry);
                if(queue.size()>k){
                    queue.poll();
                }
            }
            for(int i=k-1;i>=0;i--){
                res[i]=queue.poll().getKey();
            }
            return res;
        }
    }
    

166. 分数到小数

  • 题目描述

    image.png

  • 题解

    class Solution {
        public String fractionToDecimal(int numerator, int denominator) {
            //用哈希表记录所有被除数的下标
            //如果出现了重复的被除数,则证明出现了循环,把左括号塞到记录的下标位置,右括号放在最后
            StringBuilder sb = new StringBuilder();
            long a = numerator, b = denominator;
            if (a > 0 && b < 0 || a < 0 && b > 0) sb.append('-');
            a = Math.abs(a);
            b = Math.abs(b);
            sb.append(a / b);
            if (a % b == 0) return sb.toString();
            sb.append('.');
            Map<Long, Integer> map = new HashMap<>();
            while ((a = (a % b) * 10) > 0 && !map.containsKey(a)) {
                map.put(a, sb.length());
                sb.append(a / b);
            }
            if (a == 0) return sb.toString();
            return sb.insert(map.get(a).intValue(), '(').append(')').toString();
        }
    }
    

974. 和可被 K 整除的子数组

  • 题目描述

    image.png

  • 题解

    题目求连续子数组的和能被K整除,连续子数组的和就可以表示为前缀和的差

    比如 sum(A[i : j + 1]) = s[j + 1] - s[i]

    如果两个数的差能被K整除,就说明这两个数 mod K得到的结果相同

    只要找有多少对 mod k 相同的数就可以组合一下得到结果,

    举例 对于A= [4,5,0,-2,-3,1] K = 5 s = [0, 4, 9, 9, 7, 4, 5]

    kcnt = [2, 0, 1, 0, 4] 代表有s中有两个元素的余数都为0(即0和5)

    1个元素的余数为2(即7),四个元素的余数为4(即4994)

    所以在保证余数相同的情况下,取出两个数都可以得到一组答案

    对于这个例子答案就是 C22 + C12 + C42 = 1 + 0 + 6 = 7

    /**
    	sum[i]=A[0]+A[1]+…+A[i] 某个子数组(如下标从i到j)的和可以表示为
      A[i]+…+A[j]=sum[j]−sum[i−1]
      判断子数组的和能否被 K 整除就等价于判断 (sum[j] - sum[i-1]) mod K == 0
      等价于判断sum[j] mod K == sum[i-1] mod K
    */
    class Solution {
        public int subarraysDivByK(int[] A, int K) {
            int sum = 0, result = 0;
            Map<Integer, Integer> map = new HashMap<>();
            map.put(0, 1);
            for (int n : A) {
                sum += n;
                int curMod = (sum%K+K)%K;
                int preCount = map.getOrDefault(curMod, 0);
                result += preCount;
                map.put(curMod, preCount + 1);
            }
            return result;
        }
    }
    

O(1) 时间插入、删除和获取随机元素

  • 题目描述

    image.png

  • 题解

    class RandomizedSet {
        List<Integer> list=new ArrayList();
        Map<Integer,Integer> map=new HashMap();
        Random random=new Random();
        public RandomizedSet() {
           
        }
        
        public boolean insert(int val) {
             if(map.containsKey(val)) return false;
                map.put(val,list.size());
                list.add(list.size(),val);
                return true;
        }
        
        public boolean remove(int val) {
            if(!map.containsKey(val)) return false;
                int idx=map.get(val);
                int lastElement=list.get(list.size()-1);
                map.put(lastElement,idx);
                list.set(idx,lastElement);
                list.remove(list.size()-1);
                map.remove(val);
                return true;
        }
        
        public int getRandom() {
            return list.get(random.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();
     */
    

数组

53. 最大子数组和

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int maxSubArray(int[] nums) {
            int[] dp=new int[nums.length];
            int res=nums[0];
            dp[0]=nums[0];
            for(int i=1;i<nums.length;i++){
                dp[i]=Math.max(nums[i],dp[i-1]+nums[i]);
                res=Math.max(res,dp[i]);
            }
            return res;
        }
    }
    

33. 搜索旋转排序数组

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int search(int[] nums, int target) {
            if(nums.length==0) return -1;
            if(nums.length==1) return nums[0]==target?0:-1;
            int left=0,right=nums.length-1;
            while(left<=right){
                int mid=(left+right)/2;
                if(nums[mid]==target) return mid;
                else if(nums[mid]<nums[right]){
                    if(nums[mid]<target && target<=nums[right]){
                        left=mid+1;
                    }else{
                        right=mid-1;
                    }
                }else{
                    if(nums[left]<=target && target<nums[mid]){
                        right=mid-1;
                    }else{
                        left=mid+1;
                    }
                }
            }
            return -1;
        }
    }
    

4. 寻找两个正序数组的中位数

  • 题目描述

    image.png

  • 题解

    class Solution {
           public double findMedianSortedArrays(int[] nums1, int[] nums2) {
            int length1 = nums1.length, length2 = nums2.length;
            int totalLength = length1 + length2;
            if (totalLength % 2 == 1) {
                int midIndex = totalLength / 2;
                double median = getKthElement(nums1, nums2, midIndex + 1);
                return median;
            } else {
                int midIndex1 = totalLength / 2 - 1, midIndex2 = totalLength / 2;
                double median = (getKthElement(nums1, nums2, midIndex1 + 1) + getKthElement(nums1, nums2, midIndex2 + 1)) / 2.0;
                return median;
            }
        }
    
        public int getKthElement(int[] nums1, int[] nums2, int k) {
            int length1 = nums1.length, length2 = nums2.length;
            int index1 = 0, index2 = 0;
            int kthElement = 0;
    
            while (true) {
                // 边界情况
                if (index1 == length1) {
                    return nums2[index2 + k - 1];
                }
                if (index2 == length2) {
                    return nums1[index1 + k - 1];
                }
                if (k == 1) {
                    return Math.min(nums1[index1], nums2[index2]);
                }
                
                // 正常情况
                int half = k / 2;
                int newIndex1 = Math.min(index1 + half, length1) - 1;
                int newIndex2 = Math.min(index2 + half, length2) - 1;
                int pivot1 = nums1[newIndex1], pivot2 = nums2[newIndex2];
                if (pivot1 <= pivot2) {
                    k -= (newIndex1 - index1 + 1);
                    index1 = newIndex1 + 1;
                } else {
                    k -= (newIndex2 - index2 + 1);
                    index2 = newIndex2 + 1;
                }
            }
        }
    }
    

48. 旋转图像

  • 题目描述

    image.png

  • 题解

    class Solution {
        public void rotate(int[][] matrix) {
            int n=matrix.length;
            for(int i=0;i<n/2;i++){
                for(int j=0;j<(n+1)/2;j++){
                    int temp=matrix[i][j];
                    matrix[i][j]=matrix[n-j-1][i];
                    matrix[n-j-1][i]=matrix[n-i-1][n-j-1];
                    matrix[n-i-1][n-j-1]=matrix[j][n-i-1];
                    matrix[j][n-i-1]=temp;
                }
            }
        }
    }
    

560. 和为 K 的子数组

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int subarraySum(int[] nums, int k) {
            //扫描一遍数组, 使用map记录出现同样的和的次数
            //对每个i计算累计和sum并判断map内是否有sum-k
            Map<Integer,Integer> map=new HashMap<>();
            map.put(0,1);
            int sum=0,res=0;
            for(int i=0;i<nums.length;i++){
                sum+=nums[i];
                if(map.containsKey(sum-k)){
                    res+=map.get(sum-k);
                }
                map.put(sum,map.getOrDefault(sum,0)+1);
            }
            return res;
        }
    }
    

56. 合并区间

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int[][] merge(int[][] intervals) {
            List<int[]> res=new LinkedList<>();
            Arrays.sort(intervals,(o1,o2)->Integer.compare(o1[0],o2[0]));
            int start=intervals[0][0];
            for(int i=1;i<intervals.length;i++){
                if(intervals[i][0]>intervals[i-1][1]){
                    res.add(new int[]{start,intervals[i-1][1]});
                    start=intervals[i][0];
                }else{
                    intervals[i][1]=Math.max(intervals[i][1],intervals[i-1][1]);
                }
            }
            res.add(new int[]{start,intervals[intervals.length-1][1]});
            return res.toArray(new int[res.size()][]);
        }
    }
    

15. 三数之和

  • 题目描述

    image.png

  • 题解

    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            List<List<Integer>> res=new ArrayList<>();
            if(nums.length==0) return res;
            Arrays.sort(nums);
            for(int i=0;i<nums.length;i++){
                if(nums[i]>0) break;
                if(i>0 && nums[i]==nums[i-1]) continue;
                int j=i+1,k=nums.length-1;
                while(j<k){
                    int sum=nums[i]+nums[j]+nums[k];
                    if(sum==0){
                        res.add(Arrays.asList(nums[i],nums[j],nums[k]));
                        while(j<k && nums[j]==nums[j+1]) j++;
                        while(j<k && nums[k]==nums[k-1]) k--;
                        j++;
                        k--;
                    }else if(sum>0){
                        k--;
                    }else{
                        j++;
                    }
                }
            }
            return res;
        }
    }
    

121. 买卖股票的最佳时机

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int maxProfit(int[] prices) {
            int[][] dp=new int[prices.length][2];
            dp[0][0]=-prices[0];
            for(int i=1;i<prices.length;i++){
                dp[i][0]=Math.max(dp[i-1][0],-prices[i]);
                dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
            }
            return dp[prices.length-1][1];
        }
    }
    

39. 组合总和

  • 题目描述

    image.png

  • 题解

    class Solution {
        List<List<Integer>> res=new ArrayList<>();
        List<Integer> temp=new ArrayList<>();
        public List<List<Integer>> combinationSum(int[] candidates, int target) {
            Arrays.sort(candidates);
            backtracking(candidates,target,0,0);
            return res;
        }
        public void backtracking(int[] candidates ,int target,int startIndex,int sum){
            if(sum==target){
                res.add(new ArrayList(temp));
                return;
            }
            for(int i=startIndex;i<candidates.length;i++){
                if(sum+candidates[i]>target) break;
                temp.add(candidates[i]);
                sum+=candidates[i];
                backtracking(candidates,target,i,sum);
                sum-=temp.get(temp.size()-1);
                temp.remove(temp.size()-1);
            }
        }
    }
    

152. 乘积最大子数组

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int maxProduct(int[] nums) {
            //一个保存最大的,一个保存最小的
            int max = Integer.MIN_VALUE, imax = 1, imin = 1;
            for(int i=0; i<nums.length; i++){
                //如果数组的数是负数,那么会导致最大的变最小的,最小的变最大的。因此交换两个的值
                if(nums[i] < 0){ int tmp = imax; imax = imin; imin = tmp;} 
                imax = Math.max(imax*nums[i], nums[i]);
                imin = Math.min(imin*nums[i], nums[i]);  
                max = Math.max(max, imax);
            }
            return max;
        }
    }
    

153. 寻找旋转排序数组中的最小值

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int findMin(int[] nums) {
            int low = 0;
            int high = nums.length - 1;
            while (low <high) {
                int mid = low + (high - low) / 2;
                if (nums[mid] < nums[high]) {
                    high = mid;
                } else {
                    low = mid + 1;
                }
            }
            return nums[low];
        }
    }
    

64. 最小路径和

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int minPathSum(int[][] grid) {
            int m=grid.length,n=grid[0].length;
            int[][] dp=new int[m][n];
            dp[0][0]=grid[0][0];
            for(int i=1;i<m;i++)dp[i][0]+=dp[i-1][0]+grid[i][0];
            for(int j=1;j<n;j++)dp[0][j]+=dp[0][j-1]+grid[0][j];
            for(int i=1;i<m;i++){
                for(int j=1;j<n;j++){
                    dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j];
                }
            }
            return dp[m-1][n-1];
        }
    }
    

34. 在排序数组中查找元素的第一个和最后一个位置

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int[] searchRange(int[] nums, int target) {
            int[] res=new int[]{-1,-1};
            if(nums.length==0) return res;
            res[0]=searchBorder(nums,target,true);
            res[1]=searchBorder(nums,target,false);
            return res;
        }
        public int searchBorder(int[] nums,int target,boolean leftOrRight){
            int temp=-1;
            int left=0,right=nums.length-1;
            while(left<=right){
                int mid=(left+right)/2;
                if(nums[mid]<target){
                    left=mid+1;
                }else if(nums[mid]>target){
                    right=mid-1;
                }else{
                    temp=mid;
                    if(leftOrRight){
                        right=mid-1;
                    }else{
                        left=mid+1;
                    }
                }
            }
            return temp;
        }
    }
    

189. 轮转数组

  • 题目描述

    image.png

  • 题解

    class Solution {
        public void rotate(int[] nums, int k) {
            //取模取模取模
            int len=nums.length;
            k%=len;
            //先翻转前n-k个
            reserve(nums,0,len-1-k);
            //在翻转倒数k个
            reserve(nums,len-k,len-1);
            //整体反转
            reserve(nums,0,len-1);
        }
    
        public void reserve(int[] nums,int start,int end){
            while(start<=end){
                int temp=nums[start];
                nums[start]=nums[end];
                nums[end]=temp;
                start++;
                end--;
            }
        }
    }
    

41. 缺失的第一个正数

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int firstMissingPositive(int[] nums) {
            int len = nums.length;
            if (len == 0) {
                return 1;
            }
            for (int i = 0; i < len; ++i) {
                //需要考虑指针移动情况,大于0,小于len+1,不等与i+1,两个交换的数相等时,防止死循环
                while (nums[i] > 0 && nums[i] < len + 1 && nums[i] != i+1 && nums[i] != nums[nums[i]-1]) {
                    swap(nums,i,nums[i] - 1);               
                }
            }
            //遍历寻找缺失的正整数
            for (int i = 0; i < len; ++i) {
                if(nums[i] != i+1) {
                    return i+1;
                }
            }
            return len + 1;
        }
        //交换
       public void swap(int[] nums, int i, int j) {
           int temp = nums[i];
           nums[i] = nums[j];
           nums[j] = temp;
        }
    }
    

排序

179. 最大数

  • 题目描述

    image.png

  • 题解

    class Solution {
        public String largestNumber(int[] nums) {
            int n = nums.length;
            // 转换成包装类型,以便传入 Comparator 对象(此处为 lambda 表达式)
            Integer[] numsArr = new Integer[n];
            for (int i = 0; i < n; i++) {
                numsArr[i] = nums[i];
            }
    
            Arrays.sort(numsArr, (x, y) -> {
                long sx = 10, sy = 10;
                while (sx <= x) {
                    sx *= 10;
                }
                while (sy <= y) {
                    sy *= 10;
                }
                return (int) (-sy * x - y + sx * y + x);
            });
    
            if (numsArr[0] == 0) {
                return "0";
            }
            StringBuilder ret = new StringBuilder();
            for (int num : numsArr) {
                ret.append(num);
            }
            return ret.toString();
        }
    }
    

56. 合并区间

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int[][] merge(int[][] intervals) {
            List<int[]> res=new LinkedList<>();
            Arrays.sort(intervals,(o1,o2)->Integer.compare(o1[0],o2[0]));
            int start=intervals[0][0];
            for(int i=1;i<intervals.length;i++){
                if(intervals[i][0]>intervals[i-1][1]){
                    res.add(new int[]{start,intervals[i-1][1]});
                    start=intervals[i][0];
                }else{
                    intervals[i][1]=Math.max(intervals[i][1],intervals[i-1][1]);
                }
            }
            res.add(new int[]{start,intervals[intervals.length-1][1]});
            return res.toArray(new int[res.size()][]);
        }
    }
    

148. 排序链表

  • 题目描述

    image.png

  • 题解

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode() {}
     *     ListNode(int val) { this.val = val; }
     *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
     * }
     */
    class Solution {
        /**
         * 参考:Sort List——经典(链表中的归并排序) 
         * 
         * 归并排序法:在动手之前一直觉得空间复杂度为常量不太可能,因为原来使用归并时,都是 O(N)的,
         * 需要复制出相等的空间来进行赋值归并。对于链表,实际上是可以实现常数空间占用的(链表的归并
         * 排序不需要额外的空间)。利用归并的思想,递归地将当前链表分为两段,然后merge,分两段的方
         * 法是使用 fast-slow 法,用两个指针,一个每次走两步,一个走一步,知道快的走到了末尾,然后
         * 慢的所在位置就是中间位置,这样就分成了两段。merge时,把两段头部节点值比较,用一个 p 指向
         * 较小的,且记录第一个节点,然后 两段的头一步一步向后走,p也一直向后走,总是指向较小节点,
         * 直至其中一个头为NULL,处理剩下的元素。最后返回记录的头即可。
         * 
         * 主要考察3个知识点,
         * 知识点1:归并排序的整体思想
         * 知识点2:找到一个链表的中间节点的方法
         * 知识点3:合并两个已排好序的链表为一个新的有序链表
         */
        public ListNode sortList(ListNode head) {
            return head == null ? null : mergeSort(head);
        }
    
        private ListNode mergeSort(ListNode head) {
            if (head.next == null) {
                return head;
            }
            ListNode p = head, q = head, pre = null;
            while (q != null && q.next != null) {
                pre = p;
                p = p.next;
                q = q.next.next;
            }
            pre.next = null;
            ListNode l = mergeSort(head);
            ListNode r = mergeSort(p);
            return merge(l, r);
        }
    
        ListNode merge(ListNode l, ListNode r) {
            ListNode dummyHead = new ListNode(0);
            ListNode cur = dummyHead;
            while (l != null && r != null) {
                if (l.val <= r.val) {
                    cur.next = l;
                    cur = cur.next;
                    l = l.next;
                } else {
                    cur.next = r;
                    cur = cur.next;
                    r = r.next;
                }
            }
            if (l != null) {
                cur.next = l;
            }
            if (r != null) {
                cur.next = r;
            }
            return dummyHead.next;
        }
    }
    

剑指 Offer 45. 把数组排成最小的数

  • 题目描述

    image.png

  • 题解

    /**
    	规定 排序判断规则为:快排
    	若拼接字符串 x + y > y + xx+y>y+x ,则 xx “大于” yy 
    	反之,若 x + y < y + xx+y<y+x ,则 xx “小于” yy 
    */
    class Solution {
        public String minNumber(int[] nums) {
            String[] strs = new String[nums.length];
            for (int i = 0; i < nums.length; i++) {
                strs[i] = String.valueOf(nums[i]);
            }
            quickSort(strs, 0, strs.length - 1);
            StringBuilder res = new StringBuilder();
            for (String s : strs)
                res.append(s);
            return res.toString();
        }
    
        public void quickSort(String[] strs, int low, int high) {
            if (low < high) {
                int middle = getMiddle(strs, low, high);
                quickSort(strs, low, middle - 1);
                quickSort(strs, middle + 1, high);
            }
        }
    
        public int getMiddle(String[] strs, int low, int high) {
            //数组的第一个数为基准元素
            String temp = strs[low];
            while (low < high) {
                //从后向前找比基准小的数
                while (low < high && (strs[high] + temp).compareTo(temp + strs[high]) >= 0)
                    high--;
                //把比基准小的数移到低端
                strs[low] = strs[high];
                //从前向后找比基准大的数
                while (low < high && (strs[low] + temp).compareTo(temp + strs[low]) <= 0)
                    low++;
                //把比基准大的数移到高端
                strs[high] = strs[low];
            }
            strs[low] = temp;
            return low;
        }
    }
    

912. 排序数组

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int[] sortArray(int[] nums) {
        if(nums.length <=1)return nums;
         //qSort(nums,0,nums.length-1);
            //selectSort(nums);
            // insertSort(nums);
            // shellSort(nums);
            // bucketSort(nums);
            // countSort(nums);
            // mergeSort(nums,0,nums.length-1);
            heapSort(nums);
        return nums;
        }
    
        //快排
        void qSort(int[] arr,int s,int e){
            int l = s, r = e;
            if(l < r){
                int temp = arr[l];
                while(l < r){
                    while(l < r && arr[r] >= temp) r--;
                    if(l < r) arr[l] = arr[r];
                    while(l < r && arr[l] < temp) l++;
                    if(l < r) arr[r] = arr[l];
                }
                arr[l] = temp;
                qSort(arr,s,l);
                qSort(arr,l + 1, e);
            }
        }
        //选择排序
        void selectSort(int[] arr){
            int min;
            for(int i = 0;i<arr.length;i++){
                min = i;
                for(int j = i;j<arr.length;j++){
                    if(arr[j] < arr[min]){
                        min = j;
                    }
                }
                if(min != i) {
                    int temp = arr[i];
                    arr[i] = arr[min];
                    arr[min] = temp;
                }
            }
        }
        /**
         *
         * 插入排序:数列前面部分看为有序,依次将后面的无序数列元素插入到前面的有序数列中,初始状态有序数列仅有一个元素,即首元素。在将无序数列元素插入有序数列的过程中,采用了逆序遍历有序数列,相较于顺序遍历会稍显繁琐,但当数列本身已近排序状态效率会更高。
         *
         * 时间复杂度:O(N2)   稳定性:稳定
         * @param arr
         */
        public void insertSort(int arr[]){
            for(int i = 1; i < arr.length; i++){
                int rt = arr[i];
                for(int j = i - 1; j >= 0; j--){
                    if(rt < arr[j]){
                        arr[j + 1] = arr[j];
                        arr[j] = rt;
                    }else{
                        break;
                    }
                }
            }
        }
        /**
         * 希尔排序 - 插入排序的改进版。为了减少数据的移动次数,在初始序列较大时取较大的步长,通常取序列长度的一半,此时只有两个元素比较,交换一次;之后步长依次减半直至步长为1,即为插入排序,由于此时序列已接近有序,故插入元素时数据移动的次数会相对较少,效率得到了提高。
         *
         * 时间复杂度:通常认为是O(N3/2) ,未验证  稳定性:不稳定
         * @param arr
         */
        void shellSort(int arr[]){
            int d = arr.length >> 1;
            while(d >= 1){
                for(int i = d; i < arr.length; i++){
                    int rt = arr[i];
                    for(int j = i - d; j >= 0; j -= d){
                        if(rt < arr[j]){
                            arr[j + d] = arr[j];
                            arr[j] = rt;
                        }else break;
                    }
                }
                d >>= 1;
            }
        }
        /**
         * 桶排序 - 实现线性排序,但当元素间值得大小有较大差距时会带来内存空间的较大浪费。首先,找出待排序列中得最大元素max,申请内存大小为max + 1的桶(数组)并初始化为0;然后,遍历排序数列,并依次将每个元素作为下标的桶元素值自增1;
         * 最后,遍历桶元素,并依次将值非0的元素下标值载入排序数列(桶元素>1表明有值大小相等的元素,此时依次将他们载入排序数列),遍历完成,排序数列便为有序数列。
         *
         * 时间复杂度:O(x*N)   稳定性:稳定
         * @param arr
         */
         void bucketSort(int[] arr){
            int[] bk = new int[50000 * 2 + 1];
            for(int i = 0; i < arr.length; i++){
                bk[arr[i] + 50000] += 1;
            }
            int ar = 0;
            for(int i = 0; i < bk.length; i++){
                for(int j = bk[i]; j > 0; j--){
                    arr[ar++] = i - 50000;
                }
            }
        }
            /**
         * 基数排序 - 桶排序的改进版,桶的大小固定为10,减少了内存空间的开销。首先,找出待排序列中得最大元素max,并依次按max的低位到高位对所有元素排序;
         * 桶元素10个元素的大小即为待排序数列元素对应数值为相等元素的个数,即每次遍历待排序数列,桶将其按对应数值位大小分为了10个层级,桶内元素值得和为待排序数列元素个数。
         * @param arr
         */
         void countSort(int[] arr){
            int[] bk = new int[19];
            Integer max = Integer.MIN_VALUE;
            for(int i = 0; i < arr.length; i++){
                if(max < Math.abs(arr[i])) max = arr[i];
            }
            if(max < 0) max = -max;
            max = max.toString().length();
            int [][] bd = new int[19][arr.length];
            for(int k = 0; k < max; k++) {
                for (int i = 0; i < arr.length; i++) {
                    int value = (int)(arr[i] / (Math.pow(10,k)) % 10);
                    bd[value+9][bk[value+9]++] = arr[i];
                }
                int fl = 0;
                for(int l = 0; l < 19; l++){
                    if(bk[l] != 0){
                        for(int s = 0; s < bk[l]; s++){
                            arr[fl++] = bd[l][s];
                        }
                    }
                }
                bk = new int[19];
                fl = 0;
            }
        }
        
        /**
         * 归并排序 - 采用了分治和递归的思想,递归&分治-排序整个数列如同排序两个有序数列,依次执行这个过程直至排序末端的两个元素,再依次向上层输送排序好的两个子列进行排序直至整个数列有序(类比二叉树的思想,from down to up)。
         *
         * 时间复杂度:O(NlogN)   稳定性:稳定
         * @param arr
         */
         void mergeSortInOrder(int[] arr,int bgn,int mid, int end){
            int l = bgn, m = mid +1, e = end;
            int[] arrs = new int[end - bgn + 1];
            int k = 0;
            while(l <= mid && m <= e){
                if(arr[l] < arr[m]){
                    arrs[k++] = arr[l++];
                }else{
                    arrs[k++] = arr[m++];
                }
            }
            while(l <= mid){
                arrs[k++] = arr[l++];
            }
            while(m <= e){
                arrs[k++] = arr[m++];
            }
            for(int i = 0; i < arrs.length; i++){
                arr[i + bgn] = arrs[i];
            }
        }
         void mergeSort(int[] arr, int bgn, int end)
        {
            if(bgn >= end){
                return;
            }
            int mid = (bgn + end) >> 1;
            mergeSort(arr,bgn,mid);
            mergeSort(arr,mid + 1, end);
            mergeSortInOrder(arr,bgn,mid,end);
        }
        
        /**
         * 堆排序 - 堆排序的思想借助于二叉堆中的最大堆得以实现。首先,将待排序数列抽象为二叉树,并构造出最大堆;然后,依次将最大元素(即根节点元素)与待排序数列的最后一个元素交换(即二叉树最深层最右边的叶子结点元素);
         * 每次遍历,刷新最后一个元素的位置(自减1),直至其与首元素相交,即完成排序。
         *
         * 时间复杂度:O(NlogN)   稳定性:不稳定
         *
         * @param arr
         */
         void heapSort(int[] nums) {
            int size = nums.length;
            for (int i = size/2-1; i >=0; i--) {
                adjust(nums, size, i);
            }
            for (int i = size - 1; i >= 1; i--) {
                int temp = nums[0];
                nums[0] = nums[i];
                nums[i] = temp;
                adjust(nums, i, 0);
            }
        }
        void adjust(int []nums, int len, int index) {
            int l = 2 * index + 1;
            int r = 2 * index + 2;
            int maxIndex = index;
            if (l<len&&nums[l]>nums[maxIndex])maxIndex = l;
            if (r<len&&nums[r]>nums[maxIndex])maxIndex = r;
            if (maxIndex != index) {
                int temp = nums[maxIndex];
                nums[maxIndex] = nums[index];
                nums[index] = temp;
                adjust(nums, len, maxIndex);
            }
        }
    }
    

双指针

15. 三数之和

  • 题目描述

    image.png

  • 题解

    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            List<List<Integer>> res=new ArrayList<>();
            if(nums.length==0) return res;
            Arrays.sort(nums);
            for(int i=0;i<nums.length;i++){
                if(nums[i]>0) break;
                if(i>0 && nums[i]==nums[i-1]) continue;
                int j=i+1,k=nums.length-1;
                while(j<k){
                    int sum=nums[i]+nums[j]+nums[k];
                    if(sum==0){
                        res.add(Arrays.asList(nums[i],nums[j],nums[k]));
                        while(j<k && nums[j]==nums[j+1]) j++;
                        while(j<k && nums[k]==nums[k-1]) k--;
                        j++;
                        k--;
                    }else if(sum>0){
                        k--;
                    }else{
                        j++;
                    }
                }
            }
            return res;
        }
    }
    

141. 环形链表

  • 题目描述

    image.png

  • 题解

    public class Solution {
        public boolean hasCycle(ListNode head) {
            ListNode fast=head;
            ListNode slow=head;
            while(fast!=null && fast.next!=null){
                fast=fast.next.next;
                slow=slow.next;
                if(slow==fast){
                    return true;
                }
            }
            return false;
        }
    }
    

142. 环形链表 II

  • 题目描述

    image.png

  • 题解

    public class Solution {
        public ListNode detectCycle(ListNode head) {
            if(head==null) return head;
            ListNode fast=head;
            ListNode slow=head;
            while(fast!=null && fast.next!=null){
                fast=fast.next.next;
                slow=slow.next;
                if(fast==slow){
                    fast=head;
                    while(fast!=slow){
                        fast=fast.next;
                        slow=slow.next;
                    }
                    return slow;
                }
            }
            return null;
        }
    }
    

剑指 Offer 04. 二维数组中的查找

  • 题目描述

    image.png

  • 题解

    从右上角开始走,利用这个顺序关系可以在O(m+n)的复杂度下解决这个题:

    • 如果当前位置元素比target小,则row++
    • 如果当前位置元素比target大,则col--
    • 如果相等,返回true
    • 如果越界了还没找到,说明不存在,返回false
    class Solution {
        public boolean findNumberIn2DArray(int[][] matrix, int target) {
            if(matrix == null || matrix.length == 0) {
                return false;
            }
            int m = matrix.length, n = matrix[0].length;
            int row = 0, col = n - 1;
            while(row < m && col >= 0) {
                if(matrix[row][col] > target) {
                    col--;
                }else if(matrix[row][col] < target) {
                    row++;
                }else {
                    return true;
                }
            }
            return false;
        }
    }
    

88. 合并两个有序数组

  • 题目描述

    image.png

  • 题解

    class Solution {
        public void merge(int[] nums1, int m, int[] nums2, int n) {
            int p1=0,p2=0,cur=0;
            int[] sorted=new int[m+n];
            while(p1<m || p2<n){
                if(p1==m){
                    cur=nums2[p2++];
                }else if(p2==n){
                    cur=nums1[p1++];
                }else if(nums1[p1]<nums2[p2]){
                    cur=nums1[p1++];
                }else{
                    cur=nums2[p2++];
                }
                sorted[p1+p2-1]=cur;
            }
            for(int i=0;i<sorted.length;i++){
                nums1[i]=sorted[i];
            }
        }
    }
    

287. 寻找重复数

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int findDuplicate(int[] nums) {
            /**
            快慢指针思想, fast 和 slow 是指针, nums[slow] 表示取指针对应的元素
            注意 nums 数组中的数字都是在 1 到 n 之间的(在数组中进行游走不会越界),
            因为有重复数字的出现, 所以这个游走必然是成环的, 环的入口就是重复的元素, 
            即按照寻找链表环入口的思路来做
            **/
            int fast = 0, slow = 0;
            while(true) {
                fast = nums[nums[fast]];
                slow = nums[slow];
                if(slow == fast) {
                    fast = 0;
                    while(nums[slow] != nums[fast]) {
                        fast = nums[fast];
                        slow = nums[slow];
                    }
                    return nums[slow];
                }
            }
        }
    }
    

80. 删除有序数组中的重复项 II

  • 题目描述

    image.png

    image.png

  • 题解

    本题要求相同元素最多出现两次而非一次,所以我们需要检查上个应该被保留的元素nums[slow−2] 是否和当前待检查元素nums[fast] 相同。当且仅当 nums[slow−2]=nums[fast] 时,当前待检查元素nums[fast] 不应该被保留(因为此时必然有 nums[slow−2]=nums[slow−1]=nums[fast])。最后slow 即为处理好的数组的长度。

    特别地,数组的前两个数必然可以被保留,因此对于长度不超过 2 数组,我们无需进行任何处理,对于长度超过 2 的数组,我们直接将双指针的初始值设为 2 即可

    class Solution {
        public int removeDuplicates(int[] nums) {
            int n = nums.length;
            if (n <= 2) {
                return n;
            }
            int slow = 2, fast = 2;
            while (fast < n) {
                if (nums[slow - 2] != nums[fast]) {
                    nums[slow] = nums[fast];
                    ++slow;
                }
                ++fast;
            }
            return slow;
        }
    }
    

986. 区间列表的交集

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
            List<int[]> ans = new ArrayList();
            int i = 0, j = 0;
            while (i < firstList.length && j < secondList.length) {
            // Let's check if A[i] intersects B[j].
            // lo - the startpoint of the intersection
            // hi - the endpoint of the intersection
            int lo = Math.max(firstList[i][0], secondList[j][0]);
            int hi = Math.min(firstList[i][1], secondList[j][1]);
            if (lo <= hi)
            ans.add(new int[]{lo, hi});
            // Remove the interval with the smallest endpoint
            if (firstList[i][1] < secondList[j][1])
                i++;
            else
                j++;
            }
            return ans.toArray(new int[ans.size()][]);
        }
    }
    

二分查找

33. 搜索旋转排序数组

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int search(int[] nums, int target) {
            if(nums.length==0) return -1;
            if(nums.length==1) return nums[0]==target?0:-1;
            int left=0,right=nums.length-1;
            while(left<=right){
                int mid=(left+right)/2;
                if(nums[mid]==target) return mid;
                else if(nums[mid]<nums[right]){
                    if(nums[mid]<target && target<=nums[right]){
                        left=mid+1;
                    }else{
                        right=mid-1;
                    }
                }else{
                    if(nums[left]<=target && target<nums[mid]){
                        right=mid-1;
                    }else{
                        left=mid+1;
                    }
                }
            }
            return -1;
        }
    }
    

4. 寻找两个正序数组的中位数

240. 搜索二维矩阵 II

  • 题目描述

    image.png

  • 题解

    class Solution {
        public boolean searchMatrix(int[][] matrix, int target) {
            int m = matrix.length, n = matrix[0].length;
            int x = 0, y = n - 1;
            while (x < m && y >= 0) {
                if (matrix[x][y] == target) {
                    return true;
                }
                if (matrix[x][y] > target) {
                    --y;
                } else {
                    ++x;
                }
            }
            return false;
        }
    }
    

34. 在排序数组中查找元素的第一个和最后一个位置

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int[] searchRange(int[] nums, int target) {
            int[] res=new int[]{-1,-1};
            if(nums.length==0) return res;
            res[0]=searchBorder(nums,target,true);
            res[1]=searchBorder(nums,target,false);
            return res;
        }
        public int searchBorder(int[] nums,int target,boolean leftOrRight){
            int temp=-1;
            int left=0,right=nums.length-1;
            while(left<=right){
                int mid=(left+right)/2;
                if(nums[mid]<target){
                    left=mid+1;
                }else if(nums[mid]>target){
                    right=mid-1;
                }else{
                    temp=mid;
                    if(leftOrRight){
                        right=mid-1;
                    }else{
                        left=mid+1;
                    }
                }
            }
            return temp;
        }
    }
    

153. 寻找旋转排序数组中的最小值

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int findMin(int[] nums) {
            int low = 0;
            int high = nums.length - 1;
            while (low <high) {
                int mid = low + (high - low) / 2;
                if (nums[mid] < nums[high]) {
                    high = mid;
                } else {
                    low = mid + 1;
                }
            }
            return nums[low];
        }
    }
    

69. x 的平方根

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int mySqrt(int x) {
            int left = 1, right = x;
            while(left<=right){
                int mid = left + (right - left) / 2;
                if(x/mid>mid){
                    left = mid + 1;
                }else if (x / mid < mid) {
                    right=mid-1;
                }else {
                    return mid;
                }
            }
            return right;
        }
    }
    

1095. 山脉数组中查找目标值

  • 题目描述

    image.png

    image.png

  • 题解

    class Solution {
        public int findInMountainArray(int target, MountainArray mountainArr) {
            //三次二分查找:
            //  1. 全局二分 找到 最大值对应的下标
            //  2. 0~最大值 二分 查找,找得到返回
            //  3. 最大值~结尾, 二分查找,找得到返回
            int l = 0, r = mountainArr.length() - 1;
            while (l < r) {
                int mid = (l + r) / 2;
                if (mountainArr.get(mid) < mountainArr.get(mid + 1)) {
                    l = mid + 1;
                } else {
                    r = mid;
                }
            }
            int peak = l;
            int index = binarySearch(mountainArr, target, 0, peak, true);
            if (index != -1) {
                return index;
            }
            return binarySearch(mountainArr, target, peak + 1, mountainArr.length() - 1, false);
        }
    
        public int binarySearch(MountainArray mountainArr, int target, int l, int r, boolean flag) {
            if (!flag) {
                target *= -1;
            }
            while (l <= r) {
                int mid = (l + r) / 2;
                int cur = mountainArr.get(mid) * (flag ? 1 : -1);
                if (cur == target) {
                    return mid;
                } else if (cur < target) {
                    l = mid + 1;
                } else {
                    r = mid - 1;
                }
            }
            return -1;
        }
    }
    

162. 寻找峰值

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int findPeakElement(int[] nums) {
            int left = 0, right = nums.length - 1;
            while(left < right) {
                int mid = left + (right - left) / 2;
                if (nums[mid] > nums[mid + 1]) {
                    right = mid;
                } else {
                    left = mid + 1;
                }
            }
            return left;
        }
    }
    

74. 搜索二维矩阵

  • 题目描述

    image.png

  • 题解

    class Solution {
        public boolean searchMatrix(int[][] matrix, int target) {
            int m = matrix.length, n = matrix[0].length;
            int low = 0, high = m * n - 1;
            while (low <= high) {
                int mid = (high - low) / 2 + low;
                int x = matrix[mid / n][mid % n];
                if (x < target) {
                    low = mid + 1;
                } else if (x > target) {
                    high = mid - 1;
                } else {
                    return true;
                }
            }
            return false;
        }
    }
    

面试题 10.03. 搜索旋转数组

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int search(int[] arr, int target) {
            if(arr[0]==target)
                return 0;
            int l=0;
            int r=arr.length-1;
            int mid=0;
            while(l<=r){
                mid=l+(r-l)/2;
                //mid值==target,则继续往左搜寻,找到最小的索引,最小索引一定不为0
                if(arr[mid]==target){
                    while(mid>0&&arr[mid-1]==arr[mid])  mid--;
                    return mid;
                }
                //说明mid~r是递增序列,判读target是否在中间
                if(arr[mid]<arr[r]){
                    if(arr[mid]<target&&target<=arr[r]) l=mid+1;
                    else    r=mid-1;
                }
                //说明 l~mid 是递增序列,判读target是否在中间
                else if(arr[mid]>arr[r]){
                    if(arr[l]<=target&&target<arr[mid]) r=mid-1;
                    else l=mid+1;
                }
                //arr[mid]==arr[r]说明要么r~0~mid都相等,要么mid~r都相等,无论哪种r 都可以舍去
                else{
                    r--;
                }
            }
            return -1;
        }
    }
    

滑动窗口

3. 无重复字符的最长子串

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            if(s.length()==0) return 0;
            Map<Character,Integer> map=new HashMap<>();
            int left=0,max=Integer.MIN_VALUE;
            for(int right=0;right<s.length();right++){
                char cRight=s.charAt(right);
                map.put(cRight,map.getOrDefault(cRight,0)+1);
                while(map.get(cRight)>1){
                    //出现重复
                    char cLeft=s.charAt(left);
                    map.put(cLeft,map.get(cLeft)-1);
                    left++;
                }
                max=Math.max(max,right-left+1);
            }
            return max;
        }
    }
    

239. 滑动窗口最大值

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {
            int[] res=new int[nums.length-k+1];
            int index=0;
            Deque<Integer> deque=new LinkedList<>();
            for(int i=0;i<nums.length;i++){
                while(!deque.isEmpty() && deque.peek()<i-k+1){
                    deque.poll();
                }
                while(!deque.isEmpty() && nums[deque.peekLast()]<nums[i]){
                    deque.pollLast();
                }
                deque.offer(i);
                if(i>=k-1){
                    res[index++]=nums[deque.peek()];
                }
            }
            return res;
        }
    }
    

76. 最小覆盖子串

  • 题目描述

    image.png

  • 题解

    class Solution {
        public String minWindow(String s, String t) {
            if(s.length()==0) return "";
            if(t.length()>s.length()) return "";
            char[] sArr=s.toCharArray();
            char[] tArr=t.toCharArray();
            Map<Character,Integer> needMap=new HashMap<>();
            Map<Character,Integer> map=new HashMap<>();
            int left=0,maxNum=0,start=0,minLen=Integer.MAX_VALUE;
            for(char c:tArr){
                needMap.put(c,needMap.getOrDefault(c,0)+1);
            }
            for(int right=0;right<sArr.length;right++){
                char ch=sArr[right];
                map.put(ch,map.getOrDefault(ch,0)+1);
                if(map.get(ch).equals(needMap.get(ch))){
                    //满足条件的字符数
                    maxNum++;
                }
                //满足条件时缩小窗口
                while(needMap.size()==maxNum){
                    //记录当前窗口
                    if(right-left<minLen){
                        start=left;
                        minLen=right-left+1;
                    }
                    //缩小左边界
                    char cleft=sArr[left];
                    if(map.get(cleft).equals(needMap.get(cleft))){
                        maxNum--;
                    }
                    map.put(cleft,map.get(cleft)-1);
                    left++;
                }
            }
    		return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
        }
    }
    

1438. 绝对差不超过限制的最长连续子数组

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int longestSubarray(int[] nums, int limit) {
            //维护两个单调队列
            PriorityQueue<Integer> minQueue = new PriorityQueue<>(Comparator.naturalOrder());
            PriorityQueue<Integer> maxQueue = new PriorityQueue<>(Comparator.reverseOrder());
            int left = 0;
            int right = 0;
            int ans = 0;
            while (right < nums.length && left < nums.length) {
                minQueue.add(nums[right]);
                maxQueue.add(nums[right]);
                //根据窗口的最小值和最大值的差更新窗口
                if (maxQueue.peek() - minQueue.peek() <= limit) {
                    ans = Math.max(ans, right - left + 1);
                    right++;
                    continue;
                }
                maxQueue.remove((Integer) nums[left]);
                minQueue.remove((Integer) nums[left]);
                left++;
                right++;
            }
            return ans;
        }
    }
    

567. 字符串的排列

  • 题目描述

    image.png

  • 题解

    class Solution {
        public boolean checkInclusion(String s1, String s2) {
            //异位词
            int[] word = new int[26];
            for(int i = 0; i < s1.length(); i++) {
                char c = s1.charAt(i);
                word[c - 'a']++;
            }
            //滑动窗口
            for(int i = 0, j = 0; i < s2.length(); i++) {
                //消耗
                word[s2.charAt(i) - 'a']--;
                //补充
                while(word[s2.charAt(i) - 'a'] < 0) {
                    word[s2.charAt(j) - 'a']++;
                    j++;
                }
                //存在
                if(i - j + 1 == s1.length()) {
                    return true;
                }
            }
            return false;
        }
    }
    

1004. 最大连续1的个数 III

  • 题目描述

    image.png

  • 题解

    class Solution {
        public int longestOnes(int[] nums, int k) {
            int l = 0, r = 0, res = 0;
            while (r < nums.length) {
                if (nums[r] == 0) {
                    if (k == 0) {
                        while (nums[l] == 1) l++;
                        l++;
                    } else {
                        k--;
                    }
                }
                res = Math.max(res, ++r - l);
            }
            return res;
        }
    }