leetcode刷题第2天

977. 有序数组的平方

题目描述
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

思路:按正常先把整个数组平方再整个数组排序是可以的,但是考虑到题目给出的条件非递减顺序(即递增顺序),就可以利用正数部分平方后已经是非递减顺序,从而直接对负数部分平方,然后跟正数部分作比较即可。因为负数部分也是排好序的,只是是递减顺序,所以可以变换一下归并排序的指针设置,应用归并排序的思路来解决。

归并排序思想:通过比较已排序的子数组的元素,并依次合并它们,以创建一个新的已排序数组。

javascript解法:

var sortedSquares = function(nums) {
    let arr = [];
    let ng = -1;
    let len = nums.length;
    // 找到正负分界位置 ng
    for(let i = 0; i < len; i++){
        if(nums[i] < 0) { // 这里用 <=0 也可以
            ng = i;
        }else {
            break;
        }
    }
    // 归并排序:分解,排序,合并(这里合并只涉及两个子数组)
    // 合并终止条件:
    // 正负分界前面的负数数组从分界开始走到i = 0 
    // 或者 正负分界后面的正数数组从0开始走到j = len - 1
    let i = ng, j = ng + 1;
    while(i >= 0 || j < len) {
        if(i < 0) {
            arr.push(nums[j] * nums[j]);
            j++;
        }else if(j == len) {
            arr.push(nums[i] * nums[i]);
            i--;
        }else if(nums[i] * nums[i] < nums[j] * nums[j]) {
            arr.push(nums[i]*nums[i]);
            i--;
        }else {
            arr.push(nums[j]*nums[j]);
            j++;
        }
    }
    return arr;
};

209.长度最小的子数组

题目描述

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1
输入:nums = [3,2,2,3], val = 4
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

思路:如果用暴力的解法,只要把所有可能出现的连续子数组的情况都遍历一遍就可以,此时需要用到两个for循环;还可以考虑用滑动窗口的思想,滑动窗口的思想只需要一个for里面嵌套while即可。下面着重写滑动窗口的解法:

javascript解法:

出处: leetcode灵茶山艾府

var minSubArrayLen = function(target, nums) {
    const n = nums.length;
    let ans = n + 1;
    let sum = 0; // 子数组元素和
    let left = 0; // 子数组左端点
    for (let right = 0; right < n; right++) { // 枚举子数组右端点
        sum += nums[right];
        while (sum >= target) { // 满足要求
            ans = Math.min(ans, right - left + 1);
            sum -= nums[left++]; // 左端点右移
        }
    }
    return ans <= n ? ans : 0;
};

对于上面代码,有几个疑问值得思考一下:

  1. 为什么 ans 的初始值是 n + 1?

    因为我们最后要判断 return ans <= n ? ans : 0, 如果 ans 的初始值为 n ,刚好为数组长度,那么当遇到下面这种测试用例的时候就会出错:

在这里插入图片描述
因为在数组里面所有数都加上后还是比 target 小的时候,right - left + 1的值为 n + 1, 此时如果 ans 为 n,就会导致最后作三元判断的时候ans <= n从而返回错误结果:n .

  1. 为什么while的条件为 sum >= target时就可以把 right - left + 1作为一个结果?会不会出现最后 ans 对应的是sum>target而不是sum == target的情况?

    首先,如果sum < target的话,窗口有边界就会不断右移加数;当 sum 比 target 大的时候,窗口左边界就需要右移缩小区间直到sum再次比target小或者等于target,这时候不断把答案放在ans里面并没有影响,因为只要有等于target的情况出现就会更新ans;当sum直接就等于target的时候,我们就把答案放在ans里。但是这个时候还没有结束,窗口左边界还要继续向右滑动直到遍历完所有的情况。

    有没有发现,当sum > target 和 sum == target的时候,他们执行的操作其实是一样的:① 存储当前的ans, ② 窗口向右滑动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值