【算法Day2】数组 : 977.有序数组的平方 | 209.长度最小的子数组 | 54.螺旋矩阵 | 59.螺旋矩阵||

977.有序数组的平方

leetcode链接:977. 有序数组的平方

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

示例 1:

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

示例2:

  1. 输入: nums = [-7,-3,2,3,11]
  2. 输出: [4,9,9,49,121]

题目特点:原数组是从小到大排序,没要求原地排序。

第一想法:

原来以为只能原地排序,所以尝试用双指针交换元素一直找不到一个让结果从小到大排序的方法,卡了好久…后面看视频双指针法经典题目 | LeetCode:977.有序数组的平方
才发现原题目没有要求原地排序!

也明白了数组平方之后最大的元素要么在最左边要么在最右边! 可以利用这一特点并借助双指针和一个新数组,将数组平方后的最大元素放在新数组的最后一个位置,从后往前依次放置在新数组就可以让新数组按非递减顺序排序。

方法:双指针

具体是这样的:先将数组平方,然后定义双指针,左指针left指向第一个元素,右指针right指向最后一个元素,再定义一个等长新数组res,和指向新数组的最后一个元素的指针index。在while循环里,将nums[left]nums[right]较大者放入res[index],即如果nums[left] > nums[right],就将nums[left]放入res[index],然后left++ index-- 反之,right-- index--,left > right时退出循环,返回res数组即可。

Java代码:

class Solution {
    public int[] sortedSquares(int[] nums) {
            for(int i = 0; i < nums.length; i++) {
                nums[i] = nums[i] * nums[i];
            }
            int left = 0;//左指针
            int right = nums.length-1;//右指针
            int index = nums.length-1;//新数组的指针
            int[] res = new int[nums.length];
            while(left <= right) {
                //将左右指针所指元素较大者赋值给新数组
                if(nums[left] > nums[right]) {
                    res[index--] = nums[left++];
                }
                else{
                    res[index--] = nums[right--];
                }
            }
            return res;
        }
}

209.长度最小的子数组

leetcode链接:长度最小的子数组

题目:给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

  1. 输入:target = 7, nums = [2,3,1,2,4,3]
  2. 输出:2
  3. 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例2:

  1. 输入: target = 4, nums = [1,4,4]
  2. 输出: 1

示例 3:

  1. 输入: target = 11, nums = [1,1,1,1,1,1,1,1]
  2. 输出: 0

题目特点:要求长度最小,那不断取满足数组的子数组的最小长度就行,难点是如何得到满足条件的子数组。

第一想法:暴力解决哈哈。当然我们得寻求最优解,我尝试用双指针,但是双指针怎么定义和移动是核心,之前学习了双指针滑动窗口,这就是一道典型利用滑动窗口解决的题目。

方法:滑动窗口

示意图

思路:如图,先定义双指针ij ,起初都指向第一个元素。题目涉及子数组的和和子数组的最小长度,故定义一个sum记录子数组的和,定义length保存最小长度,length的值先设置成nums.length+1,后面如果存在满足条件的子数组并且长度更小就更新length,最后返回length;如果length依然等于nums.length说明不存在满足条件的子数组,返回-1。
ij之间的元素就是一个左闭右闭的窗口,当窗口的和sum >= target 就看长度length是否更小,是的话才更新length,然后窗口缩短一位l++;反之就延长一位r++。循环此过程。

不了解滑动窗口的同学可以看下这个:拿下滑动窗口! | LeetCode 209 长度最小的子数组

Java代码:

class Solution {
   public int minSubArrayLen(int target, int[] nums) {
        int i = 0;
        int sum = 0;
        int res = nums.length + 1;
        int length;
        for(int j = 0; j < nums.length; j++) {
            sum += nums[j];
            while(sum >= target) {
                length = j - i + 1;
                res = min(res, length);
                sum -= nums[i];
                i++;
            }
        }
        if(res == nums.length + 1) {
            return 0;
        }
        return res;
   }
    private int min(int a, int b) {
        return a < b ? a : b;
    }
}

54.螺旋矩阵

leetcode链接:54.螺旋矩阵

题目:给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例1
示例1

  1. 输入: matrix = [[1,2,3],[4,5,6],[7,8,9]]
  2. 输出: [1,2,3,6,9,8,7,4,5]

示例2
示例2

  1. 输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
  2. 输出:[1,2,3,4,8,12,11,10,9,5,6,7]

特点:其实不是考察算法,而是模拟过程,考察对过程中循环不变量、边界条件的处理。

思路:如图,上下左右四条边,右下左上的顺序填充,那么,上边up初始化为0,下边down初始化为m(matrix.length-1),左边初始化为0,右边初始化为n(matrix[0].length - 1),要维持循环不变量,每条边都是一样的处理思路!左闭右开,拐角处留给下一条边去处理,由外向内一圈圈画进去。
思路

Java代码:

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List list = new ArrayList<Integer>();
        int up = 0;
        int down = matrix.length-1;
        int left = 0;
        int right = matrix[0].length - 1;//
        while (up <= down && left <= right) {
            for (int l = left; l <= right; l++) {
                list.add(matrix[up][l]);
            }
            up++;
            for (int u = up; u <= down; u++) {
                list.add(matrix[u][right]);
            }
            right--;
            for (int r = right; r >= left && up <= down; r--) {
                list.add(matrix[down][r]);
            }
            down--;
            for (int d = down; d >= up && left <= right; d--) {
                list.add(matrix[d][left]);
            }
            left++;
        }
        return list;
    }
}

59.螺旋矩阵2

leetcode链接:59.螺旋矩阵2

题目:给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例 1:
示例1

  1. 输入: n = 3
  2. 输出: [[1,2,3],[8,9,4],[7,6,5]]

示例 2:

  1. 输入: n = 1
  2. 输出: [[1]]

思路:与上一题类似。关键还是转圈的逻辑,在二分搜索的区间定义,在这里又用上了!

Java代码:

class Solution {
    public int[][] generateMatrix(int n) {
        int[] arr = new int[n*n];
        for (int i = 1; i <= n*n; i++) {
            arr[i-1] =  i;
        }
        int u = 0;
        int d = n - 1;
        int l = 0;
        int r = n - 1;
        int[][] res = new int[n][n];
        int index = 0;
        while (l <= r && u <= d) {
            for(int i = l; i <= r; i++) {
                res[u][i] = arr[index++];
            }
            u++;
            for(int i = u; i <= d; i++) {
                res[i][r] = arr[index++];
            }
            r--;
            for(int i = r; i >= l; i--) {
                res[d][i] = arr[index++];
            }
            d--;
            for(int i = d; i >= u; i--) {
                res[i][l] = arr[index++];
            }
            l++;
        }
        return res;
    }
}

数组总结

数组理论

  1. 数组是存放在连续内存空间上的相同类型数据的集合。
  2. 数组不能直接修改只能覆盖,
  3. 数组可以方便的通过下标索引的方式获取到下标下对应的数据。
  4. Java二维数组,例如int[][] arr = new int[3][4];
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NLX2pdoy-1664096267769)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3cbe3a90cdb348818ce105bb68d01ea2~tplv-k3u1fbpfcp-watermark.image?)]
    可以看出,Java二维数组在内存中不是3*4的连续内存空间,而是四条的地址空间组成!

二分法

  • 暴力解法时间复杂度:O(n)
  • 二分法时间复杂度:O(logn)

典型题目:

二分法是面试常考题,不应轻视,手撕二分应该是我们必备技能。
关键是维持循环不变量,坚持对区间的定义,才能把握循环中的细节。

双指针法

典型题目:

主要分为快慢指针和相向双指针。
两个指针可以在一个for循环下完成两个for循环的工作。

  • 暴力解法时间复杂度:O(n^2)
  • 双指针时间复杂度:O(n)

关键是如何定义和移动双指针,指针从哪里开始,移动的条件是什么,啥时候移动,移动的目的是什么,移动后要继续判断什么,啥时候结束,都一定要清晰明确!

滑动窗口

典型题目:长度最小的子数组

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

其实滑动窗口也是双指针。滑动窗口,顾名思义,是要滑动的是要变化的,关键是如何移动窗口边界,达到动态更新活动窗口大小的目的。

滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)的暴力解法降为O(n)。

是一个非常巧妙的解题思路。

模拟行为

典型题目:

不涉及算法,就是单纯模拟过程。关键还是要维持循环不变量!有原则性地处理拐角和边界,不应该拆了东墙补西墙,那样的代码就算通过了也很冗余。边界条件越多就越要坚持区间定义和维持循环不变量的原则!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
用户界面: 1. 数组输入:请输入数组长度:(用户输入长度) 请输入数组的元素:(用户输入元素,以空格分隔) 数组输入成功! 2. 数组排序:请选择排序方式: 1. 升序排序 2. 降序排序 (用户选择排序方式) 排序成功! 3. 元素插入:请输入要插入的元素:(用户输入元素) 请输入要插入的位置:(用户输入位置) 插入成功! 4. 元素查找:请输入要查找的元素:(用户输入元素) 元素查找成功!该元素在数组中的位置为:(输出位置) 5. 元素删除:请输入要删除的元素:(用户输入元素) 元素删除成功! 6. 数组输出:数组元素为:(输出数组元素) 7. 输出指定位置元素:请输入要查询的位置:(用户输入位置) 该位置的元素为:(输出元素) 8. 对指定个数的数组元素求和:请输入要求和的个数:(用户输入个数) 数组元素求和为:(输出求和结果) 9. 实验报告: 本次实验设计了一个整型数组操作库,实现了数组输入、数组排序、元素插入、元素查找、元素删除、数组输出、输出指定位置元素、对指定个数的数组元素求和等功能。 在用户界面中,用户可以输入数组长度和元素,进行数组的初始化;也可以选择升序或降序排序方式,进行数组排序;可以插入元素,查找元素,删除元素;输出数组元素和指定位置的元素;求和指定个数的数组元素。 实验中,我们使用了冒泡排序算法进行数组排序,使用了数组下标进行元素插入和删除操作。同时,我们对用户的输入进行了合法性判断,保证了程序的稳定性和正确性。 本次实验让我对数组操作有了更深入的理解,也锻炼了我的编程能力和问题解决能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyJavaCoder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值