Day 2&有序数组的平方,长度最小的子数组

文章介绍了如何使用双指针法和滑动窗口法分别解决有序数组中每个数字平方后保持非递减顺序的问题,以及寻找长度最小的子数组,通过对比暴力求解的效率提升解决方案的性能。
摘要由CSDN通过智能技术生成

Day2

1.有序数组的平方

题目

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

解法1:暴力求解,即用一个for循环将数组更新为元素平方过后的数组,接着调用排序方法对新数组进行排序。

class Solution {
    public int[] sortedSquares(int[] nums) {
        for(int i = 0;i<nums.length;i++){
            nums[i]=nums[i]*nums[i];
        }
        Arrays.sort(nums);
        return nums;
    }
}

解法2:双指针法

思路:首先思考数组元素平方过后为什么会产生大小的变化,主要是因为左边的负数平方以后可能会大于右边正数的平方,因此关键在于想到:给定的一个非降序的数组,元素平方后的最大值可能是哪个?显然,最大值只有两种情况:1.最小的元素的平方 2.最大的元素的平方。 因此想到双指针法,将两个指针分别放在数组的首尾,每一次循环都是选取出元素平方后的最大值放入新数组中,元素被选取以后相当于数组首或尾去掉一个元素,即两个指针其中一个往中间靠拢,然后这两个指针所包含的新数组继续进行这个操作,直到两个指针汇合。

class Solution {
    public int[] sortedSquares(int[] nums) {
        int i = 0;
        int j = nums.length - 1;
        int[] result = new int[nums.length];
        int k = result.length - 1;
        while (i <= j) {
            if (nums[i] * nums[i] < nums[j] * nums[j]) {
                result[k--] = nums[j] * nums[j];
                j--;

            } else {
                result[k--] = nums[i] * nums[i];
                i++;
            }
        }
        return result;
    }
}

几个注意点

  • 这个题目最关键的地方就在于想到元素平方后的数组的最大值只可能在两头产生,接着利用双指针不断地缩小判断区间。
  • 关于if里面 j-- 和 i++ 的说明:第一个 if 判断条件为最左边元素的平方小于最右边元素的平方,因此将最右边元素的平方放到结果数组中,那就要将右边指针向左移动一位,接着与左指针指向的元素做判断;else的情况同理。

2.长度最小的子数组

题目

解法1:暴力求解

思路:使用两层for循环,遍历数组中所有可能的左索引到右索引组成的区间情况,只要找到了符合条件的区间,就更新数组长度result值(与上一个result判断,小于上一个result则更新),直到遍历结束,如果result还是初始值,说明返回0,否则返回result。

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX; // 最终的结果
        int sum = 0; // 子序列的数值之和
        int subLength = 0; // 子序列的长度
        for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为i
            sum = 0;
            for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= s) { // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

解法2:滑动窗口法

思路:根据暴力求解法,现在考虑用一层for循环实现滑动窗口。那么假设两个指针初始位置都在数组头,我们希望最终一个指针指向所求区间左,一个指向所求区间右,那么如果一个不动,另一个先动,就会回到暴力求解法,所以要根据区间内元素合来判断两个指针哪一个移动。

关键点在于要想到两个指针组成的滑动窗口(也就是两个指针都可以移动)是可以覆盖一个数组所有的子序列的!!!

那么就让代表最终子序列尾的指针先动,每动一次都计算子序列的和,如果满足条件,就记录此时的长度,然后通过代表子序列头的指针移动来缩小区间;如果发现和不满足条件,那就要扩大区间,就通过子序列尾的移动来扩大区间。

最终的结果是相当于滑动窗口在数组值一直遍历子序列,然后保存了满足条件的最小数组长度。

class Solution {

    // 滑动窗口
    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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值