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

977. 有序数组的平方 - 力扣(LeetCode)

状态:第一次暴力解法AC,第二次了解双指针思路后AC。

 昨天第二题的延续,暴力解法就是将数组全部更新之后进行排序。双指针解法利用了题目中说明的非递减特点,非递减也就意味着最大值只会在头尾产生,于是可以用头尾两个指针进行值判断并相向移动,用新建的数组从尾部开始存储。

值得注意的是,两种方法的时间复杂度分别为O(nlogn)O(n)。如果有不能对原数组进行更改的要求,那么双指针法在时空两个维度都优于暴力法;如果对空间复杂度的要求较高,那么暴力法还是有可取之处。

// 双指针法
int len = nums.size();
vector res(len, 0);
int i = 0, j = len-1, k = len-1;
while(i <= j){
    int left = nums[i] * nums[i];
    int right = nums[j] * nums[j];
    if(left <= right){
        res[k--] = right;
        --j;
    }else{
        res[k--] = left;
        ++i;
    }
}

return res;

209. 长度最小的子数组 - 力扣(LeetCode)

状态:暴力解法超时,想到了双指针(滑动窗口)解法的思路,但是实现的时候由于判断窗口停止循环的方法有问题,没有AC,查看示例代码之后AC。

同样是对数组的操作,这道题有了时间复杂度的限制,所以无法用暴力解法AC。想到了通过两个指针来维护一个区域,如果这个区域内的值小于目标值,就“吃”一个元素进来,即范围向右+1;如果这个区域内的值大于等于目标值,就记录一下这个区域的长度,并更新最短长度的答案,此外“吐”出一个值,即范围左-1。这个区域就是所谓的滑动窗口。下面是根据这个思路实现的代码:

// 双指针解法
int len = nums.size();
int res = INT_MAX;
int left = 0, right = 1;
int sum_i = nums[0];
while(left < len && right < len-1){
    if(sum_i < target){
        //cout << left << " " << right << " " << " " << sum_i << " " << res << endl;
        sum_i += nums[right++];
    }else{
        int res_i = right - left + 1;
        res = res < res_i ? res : res_i;
        //cout << left << " " << right << " " << " " << sum_i << " " << res << endl; 
        sum_i -= nums[left++];
    }
    
}
if(res == INT_MAX) { res = 0; }
return res;

然而,这个代码由于使用了一个while循环同时判断窗口的两端,导致了错误(还不知道怎么改)。观摩参考代码后发现不用拘泥于对两个指针的判断,而是可以利用窗口中元素总和来移动窗口。原来的思路:移动窗口左右范围,根据对应的结果再次移动窗口。现在的思路:窗口“吃”的过程较为简单,只要窗口内的元素和小于目标值即可,因此可以使用for循环;而窗口“吐”的过程是由窗口元素和大于等于目标值导致的,只要满足这个条件就可以一直“吐”,可以用while循环实现。代码如下:

// 双指针解法(滑动窗口)
int len = nums.size();
int res = INT_MAX;
int left = 0, right = 1;
int sum_i = 0;
for(int right = 0; right < len; ++right){
    sum_i += nums[right];
    while(sum_i >= target){
        int res_i = right - left + 1;
        res = res < res_i ? res : res_i;
        sum_i -= nums[left++];
    }
}
if(res == INT_MAX) { res = 0; }
return res;

时间复杂度:暴力解法O(n^2),滑动窗口O(n)。 

59. 螺旋矩阵 II - 力扣(LeetCode)

状态:没有思路,查看题解的思路后着手实现失败,仔细和答案对照修改之后AC。

属于做过也不一定能AC的题目,思路可以记住(上行从左到右,右列从上到下,下行从右到左,左列从下到上。这是一圈),但是在实现过程中有很多细节需要注意。需要重复练习。 时间复杂度O(n)

你可能感兴趣的:(算法,矩阵,数据结构)