day2 数组 | 977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵II

977. 有序数组的平方

LeetCode题目链接
思路:

  • 数组其实是有序的, 只不过负数平方之后可能成为最大数了。
  • 那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
  • 此时可以考虑双指针法了,i指向起始位置,j指向终止位置。
  • 定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。
  • 如果A[i] * A[i] < A[j] * A[j] 那么result[k–] = A[j] * A[j];
  • 如果A[i] * A[i] >= A[j] * A[j] 那么result[k–] = A[i] * A[i];

1. 双指针法

自己看了思路后写的

//双指针解法
//数组平方后,最大的数只可能在最左端取或最右端取

class Solution {
    public int[] sortedSquares(int[] nums) {
        int[] nums2 = new int[nums.length];
        int left = 0, right = nums.length-1, count = 0, k = nums.length-1;
        for(int i=0; i<nums.length; i++){
            nums[i] = nums[i]*nums[i];
        }
        while(count < nums.length){ //注意:此处不能是<num.length -1,有次在这出错了
        							//while(left<=right)在这里我觉得更好
            if(nums[left] < nums[right]){
                nums2[k] = nums[right];
                right--;
                k--;
            }
            else{
                nums2[k] = nums[left];
                left++;
                k--;
            }
            count++;
        }
        return nums2;

    }
}

解法1

  • 比我写的简洁,while循环那里也比我写得好,不知道我写的那个while循环为啥也通过了
  • 此时的时间复杂度为O(n),相对于暴力排序的解法O(n + nlog n)还是提升不少的。
  • while(left <= right),而不是我写的while(count < nums.length)

解法2

class Solution {
    public int[] sortedSquares(int[] nums) {
        int n = nums.length;
        // 两个指针分别初始化在正负子数组绝对值最大的元素索引
        int i = 0, j = n - 1;
        // 得到的有序结果是降序的
        int p = n - 1;
        int[] res = new int[n];
        // 执行双指针合并有序数组的逻辑
        while (i <= j) {
            if (Math.abs(nums[i]) > Math.abs(nums[j])) {
                res[p] = nums[i] * nums[i];
                i++;
            } else {
                res[p] = nums[j] * nums[j];
                j--;
            }
            p--;
        }
        return res;
    }
}

区别:比较的是数组两端的绝对值大小,而不是平方的大小

2. 直接调用排序算法

209. 长度最小的子数组

LeetCode题目链接

方法1 暴力求解

  • java中可以直接写【Integer.MAX_VALUE】、调用函数【Math.min(ans, j - i + 1);】
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length, sublen, result = Integer.MAX_VALUE;
        for(int i = 0;i < n; i++){
            int sum = 0;
            for(int j=i; j<n; j++){
                sum = sum + nums[j];
                if(sum>=target){
                    sublen = j-i+1;
                    result = Math.min(result,sublen);
                    break;
                }
            }
        }
        return (result==Integer.MAX_VALUE)? 0 : result;
        //如果result==Integer.MAX_VALUE,说明不存在符合条件的子数组,返回0
    }
}

  • 时间复杂度:O(n^2),其中n是数组的长度。需要遍历每个下标作为子数组的开始下标,对于每个开始下标,需要遍历其后面的下标得到长度最小的子数组。
  • 空间复杂度:O(1)O(1)。

方法2 前缀和+二分查找

  • Arrays.binarySearch(数组名, 数值S):在数组中二分查找大于等于S的第一个位置

Arrays.binarySearch 详解

  • 数组必须经过排序才可以使用此方法,否则返回下标显示不准
(1) binarySearch(Object[] a, Object key)
  • a: 要搜索的数组
  • key:要搜索的值

如果key在数组中,则返回搜索值的索引;否则返回-1或“-”(插入点)。插入点是索引键将要插入数组的那一点,即第一个大于该键的元素的索引。

技巧:

[1] 搜索值是数组元素,从0开始计数,得搜索值的索引值;
[2] 搜索值不是数组元素,且在数组范围内,从1开始计数,得“ - 插入点索引值”;
[3] 搜索值不是数组元素,且小于数组内元素,索引值为 – 1;
[4] 搜索值不是数组元素,且大于数组内元素,索引值为 – (length + 1);

(2)binarySearch(Object[] a, int fromIndex, int toIndex, Object key)
  • a:要搜索的数组
  • fromIndex:指定范围的开始处索引(包含)
  • toIndex:指定范围的结束处索引(不包含)
  • key:要搜索的值

如果要搜索的元素key在指定的范围内,则返回搜索值的索引;否则返回-1或“-”(插入点)。

技巧:

[1] 该搜索键在范围内,但不是数组元素,由1开始计数,得“ - 插入点索引值”;
[2] 该搜索键在范围内,且是数组元素,由0开始计数,得搜索值的索引值;
[3] 该搜索键不在范围内,且小于范围(数组)内元素,返回–(fromIndex + 1);
[4] 该搜索键不在范围内,且大于范围(数组)内元素,返回 –(toIndex + 1)。

方法3 双指针(滑动窗口)

  • 滑动窗口在数组中只适用于元素为正整数的数组
//滑动窗口解法
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0, right = 0;
        int n = nums.length;
        int sum = 0, sublen = Integer.MAX_VALUE;//因为最后要比较sublen有没有变小,所以最开始的时候
        										//赋值一个非常大的数
        for(right = 0; right < n; right++){
            sum = sum + nums[right];
            while(sum >= target){
                sublen = Math.min(sublen,right-left+1);
                //错误写法sublen = right - left + 1;
                sum = sum - nums[left];
                left++;
            }
        }
        return (sublen==Integer.MAX_VALUE)? 0 :sublen;
        //sublen如果还是等于MAX_VALUE,说明sublen没有变过,也就是此数组中所有的数加起来都没有≥target
    }
}

错误写法(还没写全):

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0, right = 0;
        int n = nums.length;
        int sum = 0, sublen = 0;
        while(right < n){
            sum = sum + nums[right];
            right++;
            sublen++;
            if(sum >= target){
                sum = sum - nums[left];
                left++;
                sublen = right - left + 1;
            }
        }
        return sublen;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

一些录友会疑惑为什么时间复杂度是O(n)。
不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。

59. 螺旋矩阵 II

leetcode题目链接

//看了题解后写的

class Solution {
    public int[][] generateMatrix(int n) {
        int left=0, right=n-1, top=0, bottom=n-1;
        int k=1;
        int[][] M = new int[n][n];
        while(k<=n*n){
            for(int i=left; i<=right; i++){//一定是小于等于right
                M[top][i] = k;
                k++;                
            }
            top++;
            for(int i=top; i<=bottom; i++){ //易错点:这四个for循环中M[][]中i在第一个位置还是
                                            //第二个位置非常容易错
                M[i][right] = k;
                k++;
            }
            right--;
            for(int i=right; i>=left; i--){
                M[bottom][i] = k;
                k++;
            }
            bottom--;
            for(int i=bottom; i>=top; i--){
                M[i][left] = k;
                k++;
            }
            left++;
        }
        return M;

    }
}
  • 这是看了LeetCode网站上一个题解做的,思路很清晰
  • 四个for循环依次是从左到右,从上到下,从右到左,从下到上

在这里插入图片描述

数组总结

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值