leetcode算法练习——977.有序数组的平方/209.长度最小的子数组/59.螺旋矩阵II

leetcode算法练习

977.有序数组的平方

题目链接

思路:
暴力解法:把所有数都平方 然后进行一个快排 时间 复杂的:O(nlogn) 取决于快排
双指针:设置两个指针 分别在数组的两端 定义一个一样大小的新数组 根据两个指针的变化 每次将最大的数放入新数组中 即新数组由下标从大到小更新 时间复杂度:O(n)

注意:
1. 双指针中for循环判断条件是 < 还是 <=

方法一:暴力解法

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

方法二:双指针
想到双指针的原因:因为数组是排好序的 那么一定是在数组的两边找到了最大的数 故而可以用两个指针的一个操作逐步向中间合拢的过程 从而得到一个由大到小的数组 将得到的数放入新数组中 以下标由大到小来更新

class Solution {
    public int[] sortedSquares(int[] nums) {
        int k = nums.length - 1;
        int[] result = new int[nums.length];
        // i=j时 指向的这个元素也要判断后放入reslut数组中
        // 如果是i<j 那么就会将i=j的这个元素漏判
        // 该for循环中i++ j-- 不写在for()循环条件中 因为i++ j--是要根据到底有没有取对应的元素到新数组中来决定的
        for(int i = 0, j = nums.length - 1; i <= j; ) {
            if(nums[i] * nums[i] > nums[j] * nums[j]) {
                result[k] = nums[i] * nums[i];
                k--;
                i++;
            }else {
                result[k] = nums[j] * nums[j];
                k--;
                j--;
            }
        }
        return result;
    }
}

209.长度最小的子数组

题目链接

思路:
暴力解法:两层for循环 不断寻找符合条件的子数组 时间复杂度为O(n²) 此方法会超时
滑动窗口:利用滑动窗口的思想来解决 实际还是双指针 只是取中间的集合 更像是一个滑动的窗口

注意:
1. for(j…) j是滑动窗口的起始位置还是终止位置
终止位置是要把后面的所有元素遍历一遍 才能返回以j为起始位置的集合 再去判断>= target 中 取最小的 这和暴力法没有区别了

2. 如何移动起始位置
所有j一定是表示的终止位置 起始位置需要一个动态移动的策略:当j到起始位置这个集合里面的所有元素和 >= target的时候 再去移动起始位置 这样就可以动态地调整起始位置 来去收集不同区间里的和

方法一:暴力解法

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

方法一:滑动窗口

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int j = 0;
        int sum = 0;
        int result = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            while (sum >= target) {
            	// 存放最小的和
                result = Math.min(result, i - j + 1);
                // 窗口起始位置的移动
                sum -= nums[j++];
            }
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

59.螺旋矩阵II

题目链接

思路:

注意:
1. 边界的处理 在之前二分法中 就已经做到了循环不变量 在此题也要遵循该原则 即坚持对每一条边的处理规则 从一而终选择左闭右闭[] 还是左闭右开()
2. 一共转了几圈 通过n/2来判断 而当n为奇数的时候 则需要注意 最中心的那个数要单独处理
3. for循环结束后变量i j的值就已经被改变了 可以不用去再重新定义他们的值

螺旋边界处理

class Solution {
    public int[][] generateMatrix(int n) {
        int startx = 0;
        int starty = 0;
        int offset = 0; // 定义每一圈的终止位置
        int count = 1;  // 用来计数
        int i,j;
        int[][] nums = new int[n][n];
        while(offset++ < n / 2) {
            // 每一圈的起始位置都不是固定的 所以不可能写死 例如 i = 0 
            // 起始位置提前定义好 
            // 左上到右上
            for(j = starty ; j < n - offset; j++) {
                nums[startx][j] = count++;
            }
            // j此时已变为n - offset
            // 右上到右下
            for(i = startx ; i < n - offset; i++) {
                    nums[i][j] = count++;
            }
            // i此时已变为n - offset
            // 右下到左下
            for(; j > starty; j--){
                nums[i][j] = count++;
            }
            // 左下到左上
            for(; i > startx; i--){
                nums[i][j] = count++;
            }         
            // 每转一圈 都要修改起始位置
            startx++;
            starty++;
        }
        // 如果n为奇数 最中心的位置要单独赋值
        if(n % 2 == 1) {
            nums[startx][starty] = count++;
        }
        return nums;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值