算法训练营DAY02 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

46 阅读3分钟

文章来源:代码随想录 数组Part2

977.有序数组的平方

题目链接

做题小结

这道题总体来说逻辑比较清晰,暴力先一边循环得到平方,然后使用排序排成升序。这里排序使用了冒泡。

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=i;j > 0;j--){
        if(nums[j] < nums[j-1]){
            int temp = nums[j];
            nums[j] = nums[j-1];
            nums[j-1] = temp;
        }
    }
}

return nums;

后期改进时间,使用Arrays.sort()快排。

for(int i = 0;i<nums.length;i++){
    nums[i] = nums[i]*nums[i];
}

Arrays.sort(nums);

return nums;

代码随想录方法

文章链接

接昨天的移除元素的题,这里也可以用到双指针法,具体实现为一头一尾两个指针,逐步向中间合拢,因为原数组是升序且有负数,那么最大的值肯定在一头一尾开始看。既然从最大的值开始找起,那么新的数组由大到小来更新。因为要求要升序,那么初始下标为nums.length-1

int l = 0;
int r = nums.length - 1;
int[] res = new int[nums.length];
int index = nums.length - 1;

while(l <= r){
    if(nums[l] * nums[l] > nums[r] * nums[r]){
        res[index] = nums[l] * nums[l];
        l++;
    }else{
        res[index] = nums[r] * nums[r];
        r--;
    }
    index--;
}
return res;

209.长度最小的子数组

题目链接

仔细审题很重要!!

这道题看到的第一想法是使用两个指针构造一个滑动窗口,具体实现如下。在实现过程中,一开始一直出现case不过的情况,后来一看发现是审题的时候把>=target看成了=target,遂解决。

int l = 0;
int r = 0;
int sum = nums[0];
int min = nums.length + 1;

while(r < nums.length){
    if (sum == target){
        min = Math.min(r - l + 1,min);
        if(r < nums.length - 1){
            sum += nums[++r];
            sum -= nums[l++];
        }else{
            break;
        }
    }else if(sum < target){
        if(r < nums.length - 1){
            sum += nums[++r];
        }else{
            break;
        }

    }else{
        min = Math.min(r - l + 1,min);
        sum -= nums[l++];
    }
}

if (min == nums.length + 1){
    return 0;
}
return min;

但感觉不够简便,因此转向随想录。

随想录代码

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

题目链接

螺旋矩阵的实现逻辑一如既往比较难以理清,经过随想录的讲解可知,这次也要应用循环不变量 - 左闭右开,左开右闭。

还有一个很重要的点是,这里需要将每一圈都当做一个独立的左闭右开循环,不能相互影响。因此在n的情况下,会有n/2圈需要做左闭右开循环,每圈的区间大小统一依次-1。

根据理解,实现代码如下

int[][] nums = new int[n][n];
int startX = 0, startY = 0;  // X代表行起点,Y代表猎奇点,每一圈的起始点
int count = 1;  // 矩阵中需要填写的数字
int loop = 1; // 记录当前的圈数
int i, j; // j 代表列, i 代表行;

while(loop <= n/2){

    for(j = startY;j < n-startY-1;j++){
        nums[startX][j] = count;
        count++;
    }


    for(i = startX;i< n-startX-1;i++){
        nums[i][n-startY-1] = count;
        count++;
    }

    for(j = n-startY-1;j > startY;j--){
        nums[n-startY-1][j]=count;
        count++;
    }

    for(i=n-startX-1;i > startX;i--){
        nums[i][startY] = count;
        count++;
    }

    startX++;
    startY++;
    loop++;
}

if (n % 2 == 1) { // n 为奇数时,单独处理矩阵中心的值
    nums[startX][startY] = count;
}
return nums;

结语

数组的部分到这里就结束了,总体来说学到很多,其中对我来说最主要的还是循环区间不变量和双指针(或相向双指针)的概念和应用,需要后期继续拓展磨练。

随想录总结链接