2.十天通关常见算法100题(第二天)

目录

前言:

11.滑动窗口的最大值

12.最小覆盖子串

13.最大子数组和

14.合并区间

15.轮转数组

16.除自身以外数组的乘积

17.缺失的第一个正数

18.矩阵置零

19.螺旋矩阵

20.旋转图像


前言:

纯作者做题的时候手敲的。有的题目代码,我写的可能是和常见的题解一样,有的是作者自已认为比较好理解的方法。由于是手敲,有一些是我写完copy过来的,有一些是我写完copy到做题网站的,所以会有各别题可能会有问题,如果发现请及时联系我修改,谢谢!

11.滑动窗口的最大值

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

示例 2:

输入:nums = [1], k = 1
输出:[1]

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int[] res = new int[nums.length-k+1];
        Deque<Integer> q = new LinkedList();
        for(int i=0;i<nums.length;i++){
            if(!q.isEmpty()&&i-k+1>q.getFirst()) q.pollFirst();
            while(!q.isEmpty()&&nums[q.getLast()]<nums[i]) q.pollLast();
            q.add(i);
            if(i>=k-1) res[i-k+1] = nums[q.getFirst()];
        }
        return res;
    }
}

12.最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

注意:

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。

示例 2:

输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。

示例 3:

输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。

提示:

  • m == s.length
  • n == t.length
  • 1 <= m, n <= 105
  • s 和 t 由英文字母组成
class Solution {
    public String minWindow(String s, String t) {
     if(s.length()<t.length()) return "";
     int[] s_cnt = new int[128];
     int[] t_cnt = new int[128];
     for(char c :t.toCharArray()) t_cnt[c]++;
     int res = 100010;
     int left = 0;
     for(int l=0,r=0;r<s.length();r++){
        s_cnt[s.charAt(r)]++;
        while(l<=r&&check(s_cnt,t_cnt)){
            if(r-l+1<res){
                res = r-l+1;
                left = l;
            }
            s_cnt[s.charAt(l++)]--;
        }
     }   
     if(res==100010) return "";
     return s.substring(left,left+res);
    }
    public boolean check(int[] s_cnt,int[] t_cnt){
        for(int i=0;i<128;i++){
            if(s_cnt[i]<t_cnt[i]) return false;
        }
        return true;
    }
}

13.最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

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

14.合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

提示:

  • 1 <= intervals.length <= 104
  • intervals[i].length == 2
  • 0 <= starti <= endi <= 104
class Solution {
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals,(a,b) -> Integer.compare(a[0],b[0]));
        List<int[]> res = new LinkedList();
        res.add(intervals[0]);
        for(int i=1;i<intervals.length;i++){
            int l = intervals[i][0],r = intervals[i][1];
            int[] old = res.get(res.size()-1);
            int old_l = old[0],old_r = old[1];
            if(l>old_r){
                res.add(intervals[i]);
            }else{
                int mer_l = old_l,mer_r = Math.max(r,old_r);
                res.remove(res.size()-1);
                res.add(new int[]{mer_l,mer_r});
            }
        }
        return res.toArray(new int[res.size()][]);
    }
}

15.轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1
  • 0 <= k <= 105

进阶:

  • 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
  • 你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?
class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k = k%n;
        reverse_array(0,n-1,nums);
        reverse_array(0,k-1,nums);
        reverse_array(k,n-1,nums);
    }
    public void reverse_array(int start,int end,int[] nums){
        while(start<end){
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start++;
            end--;
        }
    }
}

16.除自身以外数组的乘积

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内。

请 不要使用除法,且在 O(n) 时间复杂度内完成此题。

示例 1:

输入: nums = [1,2,3,4]
输出: [24,12,8,6]

示例 2:

输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

提示:

  • 2 <= nums.length <= 105
  • -30 <= nums[i] <= 30
  • 输入 保证 数组 answer[i] 在  32 位 整数范围内

进阶:你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 不被视为 额外空间。)

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n = nums.length;
        int[] pre = new int[nums.length];
        int[] suff = new int[nums.length];
        int[] res = new int[nums.length];
        for(int i=0;i<n;i++) res[i] = 1;
        pre[0] = nums[0];
        for(int i=1;i<n;i++) pre[i] = pre[i-1]*nums[i];
        suff[n-1] = nums[n-1];
        for(int i=n-2;i>=0;i--) suff[i] = suff[i+1]*nums[i];
        for(int i=0;i<n;i++){
            if(i>0){
                res[i] *= pre[i-1];
            }
            if(i<n-1){
                res[i] *= suff[i+1];
            }
        }
        return res;
    }
}

17.缺失的第一个正数

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:

输入:nums = [1,2,0]
输出:3
解释:范围 [1,2] 中的数字都在数组中。

示例 2:

输入:nums = [3,4,-1,1]
输出:2
解释:1 在数组中,但 2 没有。

示例 3:

输入:nums = [7,8,9,11,12]
输出:1
解释:最小的正数 1 没有出现。

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1
class Solution {
    public int firstMissingPositive(int[] nums) {
        int n  = nums.length;
        for(int i=0;i<n;i++){
            while(1<=nums[i]&&nums[i]<=n&&nums[i]!=nums[nums[i]-1]){
                int temp = nums[i];
                nums[i] = nums[temp-1];
                nums[temp-1] = temp;
            }
        }
        for(int i=0;i<n;i++){
            if(nums[i]!=i+1){
                return i+1;
            }
        }
        return n+1;
    }
}

18.矩阵置零

给定一个 m x n 的矩阵,如果一个元素为 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法

    示例 1:

    输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
    输出:[[1,0,1],[0,0,0],[1,0,1]]
    

    示例 2:

    输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
    输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]
    

    提示:

    • m == matrix.length
    • n == matrix[0].length
    • 1 <= m, n <= 200
    • -231 <= matrix[i][j] <= 231 - 1

    进阶:

    • 一个直观的解决方案是使用  O(mn) 的额外空间,但这并不是一个好的解决方案。
    • 一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
    • 你能想出一个仅使用常量空间的解决方案吗?
    class Solution {
        public void setZeroes(int[][] matrix) {
            int m = matrix.length,n=matrix[0].length;
            int[] raw = new int[m];
            int[] column = new int[n];
            for(int i=0;i<m;i++){
                for(int j=0;j<n;j++){
                    if(matrix[i][j]==0){
                        raw[i] = 1;
                        column[j] = 1;
                    }
                }
            }
            for(int i=0;i<m;i++){
                for(int j=0;j<n;j++){
                    if(raw[i]==1||column[j]==1){
                        matrix[i][j] = 0;
                    }
                }
            }
            return ;
        }
    }

    19.螺旋矩阵

    给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

    示例 1:

    输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
    输出:[1,2,3,6,9,8,7,4,5]
    

    示例 2:

    输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
    输出:[1,2,3,4,8,12,11,10,9,5,6,7]
    

    提示:

    • m == matrix.length
    • n == matrix[i].length
    • 1 <= m, n <= 10
    • -100 <= matrix[i][j] <= 100
    class Solution {
        public List<Integer> spiralOrder(int[][] matrix) {
            if(matrix==null||matrix.length==0||matrix[0].length==0) return null;
            List<Integer> res = new LinkedList();
            int m = matrix.length,n = matrix[0].length;
            int left = 0,top=0,right=n-1,bottom=m-1;
            while(left<=right&&top<=bottom){
                for(int i=left;i<=right;i++){
                    res.add(matrix[top][i]);
                }
                for(int i=top+1;i<=bottom;i++){
                    res.add(matrix[i][right]);
                }
                if(left<right&&top<bottom){
                    for(int i= right-1;i>=left;i--){
                        res.add(matrix[bottom][i]);
                    }
                    for(int i=bottom-1;i>top;i--){
                        res.add(matrix[i][left]);
                    }
                   
                }
                 top++;
                 left++;
                 bottom--;
                 right--;
            }
            return res;
        }
    }

    20.旋转图像

    给定一个 × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

    你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

    示例 1:

    输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
    输出:[[7,4,1],[8,5,2],[9,6,3]]
    

    示例 2:

    输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
    输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
    

    提示:

    • n == matrix.length == matrix[i].length
    • 1 <= n <= 20
    • -1000 <= matrix[i][j] <= 1000

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值