代码随想录算法训练营第二天|977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

 977.有序数组的平方 

题目建议: 本题关键在于理解双指针思想 

题目链接:力扣

文章讲解:代码随想录

视频讲解: 双指针法经典题目 | LeetCode:977.有序数组的平方_哔哩哔哩_bilibili

思考:数组是固定的,不仅可以从小开始,还可以从大开始。

 209.长度最小的子数组

题目建议: 本题关键在于理解滑动窗口,这个滑动窗口看文字讲解 还挺难理解的,建议大家先看视频讲解。  拓展题目可以先不做。 

题目链接:力扣

文章讲解:代码随想录

视频讲解:拿下滑动窗口! | LeetCode 209 长度最小的子数组_哔哩哔哩_bilibili

思路:没有思路,怎么想都太麻烦。参考代码随想录的文章,在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置?

连续子数组—— >滑动窗口

代码自己写:明白这个是符合条件的子数组遍历,然后取出最小的。

public int minSubArrayLen(int target, int[] nums) {
        int susum=0;//子总值
        int sublen = 0;//子长度
        int relen = nums.length;
        int sum=0;
        //双指针   
        for(int i=0,j=0;j<nums.length ;j++){
            susum+=nums[j];
            while(susum>=target){
                sublen=j-i+1;
                relen = sublen < relen ? sublen:relen;
                sum=relen;
                susum -=nums[i++] ;
        }
        }
        return sum;
    }
时间复杂度:O(n)
空间复杂度:O(1)
拓展:哈希+滑动窗口
904. 水果成篮

题目链接:904. 水果成篮

思路:求最长子数组长度,直滑动窗口模板。本题中符合条件指窗口中水果种类是2。 用HashMap记录,Map<水果种类,出现频次>, 延伸右边界时,增加频次。缩进左边界时,减少频次。 频次为0时,从map删除。 map的大小为2时,正好符合条件。

最长窗口模板
for(枚举选择)
    右边界
    while(不符合条件)
        左边界
    更新结果

代码:

public int totalFruit(int[] fruits) {
        if (fruits == null || fruits.length == 0) return 0;
        int n = fruits.length;
        Map<Integer, Integer> cnt = new HashMap<>();
        int ans = 0, left = 0;
        for (int i = 0; i < n; i++) {
            cnt.put(fruits[i], cnt.getOrDefault(fruits[i], 0) + 1);  // 右边界
            while (cnt.size() > 2) {
                cnt.put(fruits[left], cnt.get(fruits[left]) - 1);
                if (cnt.get(fruits[left]) == 0) {
                    cnt.remove(fruits[left]);
                }
                ++left;
            }
            ans = Math.max(ans, i - left + 1);
        }
        return ans;
    }
时间复杂度:O(n)
空间复杂度:O(1)

 59.螺旋矩阵II

题目建议:  本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。 

题目链接:力扣

文章讲解:代码随想录

视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II_哔哩哔哩_bilibili

思路:一开始也有想到按规律,想到每次按块分,后面的没有规律,放弃了,看了题解,发现就差一点,循环的规律还不是很清楚。

public int[][] generateMatrix(int n) {
            int[][] matrix = new int[n][n];
            int loop = 0;//循环
            int count = 1;//赋值
            int start =0;//开始的点
            int k,i;
        while(loop++ < n/2){
            for(i =start;i<n-loop ; i++){
                matrix[start][i] = count++;
            }
            for(k=start;k<n-loop  ; k++){
                matrix[k][i] = count++;
            }
            for(;i>=loop  ; i--){
                matrix[k][i] = count++;
            }
            for(;k>=loop   ; k--){
                matrix[k][i] = count++;
            }
        start++;
        } 
        if (n % 2 == 1) {
            matrix[start][start] = count;
        }
        return matrix;  
    }
时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
空间复杂度 O(1)
拓展:
54. 螺旋矩阵

54. 螺旋矩阵

剑指 Offer 29. 顺时针打印矩阵

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        //定义一个存储结果的变量。
        List<Integer> list = new ArrayList<>();
        //为空时,直接退出。
        if(matrix ==null || matrix.length ==0){
            return list;
        }
        //构造一个 m*n 的一个矩阵
        int m = matrix.length; //行
        int n = matrix[0].length; //列
        int i =0;  //层数(从外向内的层数)
        int count = (Math.min(m,n)+1)/2; //统计从外向内的总层数,至少为一层
        while(i<count){
            //从左往右
            //行不变,列逐渐增大,特被这里 n-i是为了控制他在从外到内,第几层。最外面为第0层
            // j 为变化的列
            for(int j = i;j<n-i;j++){
                list.add(matrix[i][j]);
            }
            //从上往下
            //行逐渐增大,列不变
            // j 为变化的行
            // (n-1)-i 为最右边一列
            for(int j = i+1;j<m-i;j++){
                list.add(matrix[j][(n-1)-i]);
            }
            //从右往左
            //行不变,列逐渐减小
            // j 为变化的列
            // (n-1)-(i+1) 这里的 i + 1是为了去除最右下角那个数,
            // n-1-i 指向最右边的列, j >= i 是为了保证当行为最后一行
            //这里的 (n-1-i) != i 这是用来保证,是属于同一层的
            for(int j= (n-1)-(i+1); j>= i && (m-1-i != i); j--){
                list.add(matrix[(m-1)-i][j]);
            }
            //从下往上
            //列不变,行逐渐减小
            // j 为可变的行 
            //(m-1)-(i+1) 是为了去除最左上角的数
            // j >= i+1,是为了保证当前行为第二行
            // (n-1-i) !=i 这是用来保证,是属于同一层的。
            for(int j = (m-1)-(i+1);j >= i+1 && (n-1-i) !=i; j--){
                list.add(matrix[j][i]);
            }
            i++; //层数加一,继续向内层递进
        } 
        //返回结果
        return list;

    }
}

补充:

ArrayListLinkedList各自常用的方法:

ArrayList的常用方法:

  • add(element): 将元素添加到列表的末尾。
  • add(index, element): 将元素插入到指定索引位置。
  • get(index): 获取指定索引位置的元素。
  • set(index, element): 替换指定索引位置的元素。
  • remove(index): 移除指定索引位置的元素。
  • size(): 返回列表的大小,即元素的数量。
  • isEmpty(): 判断列表是否为空。
  • contains(element): 判断列表是否包含指定元素。
  • indexOf(element): 返回指定元素在列表中首次出现的索引位置。
  • clear(): 清空列表中的所有元素。

LinkedList的常用方法:

  • add(element): 将元素添加到列表的末尾。
  • addFirst(element): 将元素添加到列表的开头。
  • addLast(element): 将元素添加到列表的末尾。
  • getFirst(): 返回列表的第一个元素。
  • getLast(): 返回列表的最后一个元素。
  • removeFirst(): 移除并返回列表的第一个元素。
  • removeLast(): 移除并返回列表的最后一个元素。
  • size(): 返回列表的大小,即元素的数量。
  • isEmpty(): 判断列表是否为空。
  • contains(element): 判断列表是否包含指定元素。
  • indexOf(element): 返回指定元素在列表中首次出现的索引位置。
  • clear(): 清空列表中的所有元素。
int numberOfRows = array.length;                 // 获取行数
int numberOfColumns = array[0].length;           // 获取列数

List转换为数组:

String[] array = list.toArray(new String[list.size()]);

数组转换为List:

List<String> list = Arrays.asList(array);
当使用Arrays.asList()方法将数组转换为List时,返回的List是一个固定大小的列表。如果需要进行添加、删除等操作,可以使用ArrayList类来创建一个可变的List对象,并将转换后的列表传递给ArrayList的构造函数。例如:List<String> mutableList = new ArrayList<>(Arrays.asList(array))。这样就可以对可变的列表进行操作了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值