代码随想录算法一刷Day02 数组 977有序数组平方 209长度最小的子数组 59 螺旋矩阵

1.基础知识

2.相关知识

3.力扣题目

3.1 977 有序数组平方

在这里插入图片描述

3.1.1 自己做法

双指针法想到了一点,但是指针运用错误。

参考做法是俩指针分别指向原数组的头尾,这样相遇时循环就可以停止。

我的做法是俩指针一个指向第一个非负数,一个指向最后一个/第一个负数,(参考先找最大数,我是先找最小数)这样一直没找到循环终止的条件(想到left<0 & right >nums.length - 1就可以停止,再得到left和right具体数,把没有到的剩下的直接插入(但感觉算法题肯定不会弄得这么繁琐就没写(哭,csdn为什么没有表情包啊啊啊啊啊))),所以没做出来。知道这点后成功写出。

class Solution {
    public int[] sortedSquares(int[] nums) {
        int[] result = new int[nums.length];
        int left = 0;
        int right = nums.length - 1;
        int index = nums.length - 1;
        for(int i = 0;i < nums.length; i++){
            nums[i] = nums[i]*nums[i];
        }

        while(left <= right){
            if(nums[left] > nums[right]){
                result[index] = nums[left];
                left++;
                index--;
            }else{
                result[index] = nums[right];
                right--;
                index--;
            }
        }
        return result;
    }
}
出现的问题(快反思)

在Java中,局部变量在使用之前必须被初始化。

3.1.2 参考做法

  1. 数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
  2. 此时的时间复杂度为O(n),暴力排序的解法O(n + nlog n)
class Solution {
    public int[] sortedSquares(int[] nums) {
        int l = 0;
        int r = nums.length - 1;
        int[] res = new int[nums.length];
        int j = nums.length - 1;
        while(l <= r){
            if(nums[l] * nums[l] > nums[r] * nums[r]){
                res[j--] = nums[l] * nums[l++];
            }else{
                res[j--] = nums[r] * nums[r--];
            }
        }
        return res;
    }
}

3.2 209 长度最小的子数组

在这里插入图片描述

3.2.1 自己做法

第一想法:循环取数组的第i个元素,然后顺着他往后相加,总和>=target之后,输出长度(存入一个数组里然后取最小输出/定义一个变量,存入这个变量,直到下一个长度出现比较,始终存最小的)
//结果:超出时间限制(代码随想录上的暴力解法也是超时(所以可能是对的吧))

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int sum = 0;
        int count = 0;
        for(int i = 0; i <= nums.length - 1; i++){
            int j = i;
            while(sum < target){
                sum = sum + nums[i];
                if(i < nums.length - 1){
                    i++;
                }else{
                    if(sum >= target){
                        i++;
                    }
                    break;
                }
            }
            if(sum >= target){
               int count2 = i - j;
                if(count == 0 | count2 < count){
                    count = count2;
                } 
            }
            i = j;
            sum = 0;
        }
        return count;
    }
}
//看完思路自己写的:和参考的区别就是一开始长度的赋值,参考为极大值,我为0.
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int sum = 0;
        int count = 0;
        for(int right = 0; right <= nums.length - 1; right++){
            sum = sum + nums[right];
            while(sum >= target){
                int count2 = right - left + 1;
                if(count != 0){
                    count = Math.min(count,count2);
                }else{
                    count = count2;
                }
                sum = sum - nums[left];
                left++;
            }
        }
        return count;
    }
}
出现的问题(快反思)
  1. 三元运算符里不能使用赋值语句。
  2. count = Math.min(count,count2);求最大max或最小值min函数

3.2.2 参考做法

数组操作中一个重要的方法:滑动窗口
滑动窗口:不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。

窗口就是满足其和 ≥ s 的长度最小的 连续子数组。
窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

(第一个和>s的子数组,结束位置少一个肯定就<s了,所以要找最小的,就要试着从起始少一个看达没达到要求,这也就是上面说的起始指针的移动)
(就是小了结束往后移,大了起始往后移)

class Solution {

    // 滑动窗口
    public int minSubArrayLen(int s, int[] nums) {
        int left = 0;
        int sum = 0;
        int result = Integer.MAX_VALUE;
        for (int right = 0; right < nums.length; right++) {
            sum += nums[right];
            while (sum >= s) {
                result = Math.min(result, right - left + 1);
                sum -= nums[left++];
            }
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

3.3 59 螺旋矩阵

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b540f0c9916041eb87486b370152767c.png

3.2.1 自己做法

第一想法:自己在IDEA上运行n=3或4成功了,但是在力扣上显示超过时间限制(循环应该用太多了,还是暴力解法)

//自己的想法是按count大小判断是否停止
public class _59 {
    public static void main(String[] args) {
        int n = 4;
        int[][] nums= new int[n][n];
        int count = 1;
        int one = 0;
        int two = 0;
        int sum = 0;
        while(count <= n * n){
            int key = 1;
            one = sum;
            two = sum;
            switch(key){
                case 1:
                    while(two < n-1-sum){
                        nums[one][two] = count;
                        two++;
                        count++;
                        if (count > n * n){
                            break;
                        }
                    }
                    if (count > n * n){
                        break;
                    }
                case 2:
                    while(one < n-1-sum){
                        nums[one][two] = count;
                        one++;
                        count++;
                        if (count > n * n){
                            break;
                        }
                    }
                    if (count > n * n){
                        break;
                    }
                case 3:
                    while(two > 0+sum){
                        nums[one][two] = count;
                        two--;
                        count++;
                        if (count > n * n){
                            break;
                        }
                    }
                    if (count > n * n){
                        break;
                    }
                case 4:
                    while(one > 0+sum){
                        nums[one][two] = count;
                        one--;
                        count++;
                        if (count > n * n){
                            break;
                        }
                    }
                    if (count > n * n){
                        break;
                    }
            }
            sum++;
        }
        for(int i = 0; i < nums.length; i++){
            for(int j = 0; j < nums[i].length; j++){
                System.out.println(nums[i][j]);
            }
        }
    }
}
//看了参考思路,用圈数作为停止条件
class Solution {
    public int[][] generateMatrix(int n) {
        int[][] nums= new int[n][n];
        int count = 1;
        int sum = 0;
        int loop = n/2;
        while(loop > 0){
            int one = sum;
            int two = sum;
            while(two < n-1-sum){
                nums[one][two] = count;
                two++;
                count++;
            }
            while(one < n-1-sum){
                nums[one][two] = count;
                one++;
                count++;
            }
            while(two > 0+sum){
                nums[one][two] = count;
                two--;
                count++;
            }
            while(one > 0+sum){
                nums[one][two] = count;
                one--;
                count++;
            }
            sum++;
            loop--;
        }
        if(n%2 == 1){
            nums[n/2][n/2] = n*n;
        }
        return nums;
    }
}
出现的问题(快反思)
  1. 这里switch的每条分支都是要顺序执行的,所以根本不用写switch,直接写要执行的语句就行了
  2. 判断条件:怎么及时地让count>n*n的时候及时停止:参考做法是按圈数判断的
  3. while(0)为假,不会执行,其他非零数均为真。(我一直把0记成-1了)(并且java中while里不能直接填常量)
  4. 自减运算符只能应用于变量,而不是直接应用于表达式。
  5. 在Java中,while循环的条件必须是一个布尔表达式,但是你使用了loop–,这是一个赋值表达式,它返回的是原始值(在自减之前)而不是布尔值。

3.2.2 参考做法

  1. 每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
  2. 循环要转n/2圈(一圈占两行,n是奇数的话,那就只剩最内圈也就是中心一个数,直接赋值n的平方就行)
class Solution {
    public int[][] generateMatrix(int n) {
        int[][] nums = new int[n][n];
        int startX = 0, startY = 0;  // 每一圈的起始点
        int offset = 1;// 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int count = 1;  // 矩阵中需要填写的数字
        int loop = 1; // 记录当前的圈数
        int i, j; // j 代表列, i 代表行;

        while (loop <= n / 2) {

            // 顶部
            // 左闭右开,所以判断循环结束时, j 不能等于 n - offset
            for (j = startY; j < n - offset; j++) {
                nums[startX][j] = count++;
            }

            // 右列
            // 左闭右开,所以判断循环结束时, i 不能等于 n - offset
            for (i = startX; i < n - offset; i++) {
                nums[i][j] = count++;
            }

            // 底部
            // 左闭右开,所以判断循环结束时, j != startY
            for (; j > startY; j--) {
                nums[i][j] = count++;
            }

            // 左列
            // 左闭右开,所以判断循环结束时, i != startX
            for (; i > startX; i--) {
                nums[i][j] = count++;
            }
            startX++;
            startY++;
            offset++;
            loop++;
        }
        if (n % 2 == 1) { // n 为奇数时,单独处理矩阵中心的值
            nums[startX][startY] = count;
        }
        return nums;
    }
}

4.总结

977:你是真菜啊,必须把排序学一遍,然后会代码,977找不到循环终止条件的时候,想着暴力解法写出来算了,然后发现自己不会写排序算法。(微笑)

59:一开始自己做的虽然知道很繁琐,空间复杂度高了,但是时间复杂度和参考的一样,一个会超时一个不会超时,所以力扣的时间限制应该蛮严格的。

今天:虽说三道题没一道顺利提交的,还做了很久。但是最起码都有思路,也是看到了一点点希望。

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值