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

相关题目

977.有序数组的平方 <->力扣链接
209.长度最小的子数组 <->力扣链接
59.螺旋矩阵II <->力扣链接

解题过程

977.有序数组的平方

自己的解题思路

拿到这道题后,首先想到使用暴力解法,每个数据平方后在进行排序,代码如下

public static int[] sortedSquares(int[] nums) {
       for (int i = 0; i < nums.length; i++) {
            nums[i] = nums[i] * nums[i];
        }
        //排序
        for (int i = 1; i < nums.length; i++) {
            for (int j = 0; j < nums.length - 1; j++) {
                if (nums[j] > nums[j + 1]) {//从小到大排序
                    int temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;
                }
            }
        }
        return nums;
   }

时间复杂度为O(n^2),题目中进阶版要求;请你设计时间复杂度为 O(n) 的算法解决本问题
如何实现呢?参考卡哥解答,总结如下:其实本题主要想考察双指针的应用,所以可是使用双指针解题。
由于**本题没有要求在原数组上进行处理,因此可是使用空间换时间,**本题中给出的原数组为有序数组,但会包含负数,
因此数组中各个元素的平方最大的值肯定在为两端的某一个,所以可定义两个指针分别指向数组头尾部,
开辟一个新的数组与原数组长度相同,由后向前遍历存储原数组剩余元素中平方最大的值。
实现代码如下

public static int[] sortedSquares(int[] nums) {
        int[] res = new int[nums.length];
        int left = 0;
        int right = nums.length - 1;
        int index = nums.length - 1;
        while (left <= right) {
            if (left == right) {
                res[index] = nums[left] * nums[left];
            }
            if (nums[left] * nums[left] > nums[right] * nums[right]) {
                res[index--] = nums[left] * nums[left];
                left++;
            } else {
                res[index--] = nums[right] * nums[right];
                right--;
            }
        }
        return res;
    }

总结:双指针在面试中的考题有很多,话不多说,继续练习

209.长度最小的子数组

这个题之前在新东方面试中考察过,因此印象比较深刻
自己的解题思路:可总结为历经坎坷
第一次尝试:使用双指针解题,设置快慢指针和求和的sum值,初始化为0,当sum值小于目标值时,fast加一,并将fast位置出的值加到sum中,当sum值大于等于目标值时,sum值减去慢指针所指向的位置值,慢指针加一
但如何记录子数组长度呢,使用fast-slow+1表示,
但这种情况只适用于最小长度数组处于数组末尾的情况,当最小长度处在数组之间怎么处理呢,这时我进行了
第二次尝试:另外定义一个数据介绍子数组长度最小值,,如图所示在这里插入图片描述就在自以为可以的时候又出现了其他场景,我一个措手不及,直接凑答案
完整代码如下:

public static int minSubArrayLen(int target, int[] nums) {
        int sum = 0;
        int fast = 0;
        int slow = 0;
        int len = 0;
        int numSum=0;
        int res = nums.length;
        //求数组所有元素之和
        for (int i = 0; i < nums.length; i++) {
            numSum+=nums[i];
        }
        //数组所有元素之和小于目标值时,说明数组中不存在对应的最小序列
        if(numSum < target){
            return 0;
        }
         //数组所有元素之和等于目标值时,说明数组中所有元素构成了最小序列
        else if(numSum == target){
            return nums.length;
        }
        //其他场景
        for (; fast < nums.length; fast++) {
            sum += nums[fast];
            while (sum >= target) {
                len = fast-slow+1;
                res = Math.min(res,len);
                sum -= nums[slow++];
            }
        }
        return res;
    }

随想录相关解释

  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;
  }

搜嘎,原来特殊情处理起来只需简单的一步,学费了

59.螺旋矩阵II

看到这个题目呢,其实早已打了退堂鼓,我这心里及其不健康的。算了,自己也没啥思路,直接看答案吧
卡哥解题思路
感觉学费了,自己动手一试,哎,有了!!!

 public static int[][] generateMatrix(int n) {
       int[][] res = new int[n][n];
       int startX = 0;
       int startY = 0;//标记每一圈的起始位置
       int i = 0;
       int j = 0;//标记行和列下标
       int offset = 1;//标记每一圈的每一步的最后一步与边界的距离
       int loop = 1;//记录当前圈数
       int count = 1;//数组中写入的数值
       while (loop <= n / 2) {
           //从左到右,i不变,j递增
           for (j = startY; j < n - offset; j++) {
           	//这里为什么要使用res[startX][j]而不是使用res[i][j]呢?因为startX和startY标记每一圈的起始位置,如果使用后者,一圈下来i和j的值都会从0开始,所以会出现错误如下图
               res[startX][j] = count++;
           }
           //从上到下,j不变,i递增
           for (i = startX; i < n - offset; i++) {
               res[i][j] = count++;
           }
           //从右到左,i不变,j递减
           for (; j > startY; j--) {
               res[i][j] = count++;
           }
           //从下到上,j不变,i递减
           for (; i > startX; i--) {
               res[i][j] = count++;
           }
           startX++;
           startY++;
           offset++;
           loop++;
       }
       //如果n为奇数,需要对中间点做特殊处理,即n^2需要做特殊处理
       if (n % 2 == 1) {
           res[startX][startY] = count;
       }
       return res;
   }
总结:

难点在于

  • 四个处理过程中i和j的初始值,即以下代码中for循环中i和j的初始化
for (j = startY; j < n - offset; j++) {
         res[startX][j] = count++;
}
 //从上到下,j不变,i递增
 for (i = startX; i < n - offset; i++) {
         res[i][j] = count++;
}

这是因为:startX和startY标记每一圈的起始位置,而四个for循环过程刚好是处理一圈,所以i和j的初始化分别为startX和startY

  • 从左到右遍历时,for循环中res[startX][j] = count++;这里为什么要使用res[startX][j]而不是使用res[i][j]呢??
    ·······因为startX和startY标记每一圈的起始位置,如果使用后者,一圈下来i和j的值都会从0开始,所以会出现错误如下图
    在这里插入图片描述
    告诫自己:遇题不要慌,再难再繁琐的题都需要我静下心来慢慢破解,总会被解决的!!!加油吧,少年
    在这里插入图片描述
  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组平方",和Leetcode 209 "长度最小数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小数组,使得数组的和大于等于给定的目标值。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现的代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二天的算法训练营的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值