学习任务:
Leetcode977.有序数组的平方
难度:简单
| 相关标签:数组、双指针、排序
-
题目: 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
-
思路: 采用双指针,数组其实是有序的, 只不过负数平方之后可能成为最大数了。那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。
如果A[i] * A[i] < A[j] * A[j] 那么result[k–] = A[j] * A[j]; 。
如果A[i] * A[i] >= A[j] * A[j] 那么result[k–] = A[i] * A[i]; 。 -
注意:
- 如果调用Java中的sort()函数排序,采用的是快速排序,其时间复杂度为O( n log n n\log{n} nlogn)
- 暴力破解时间复杂度为O(n + nlogn),双指针为O(n),
-
代码:
暴力破解:
先平方,后排序
import java.util.Arrays;
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;
}
}
双指针法:
class Solution {
public int[] sortedSquares(int[] nums) {
int l = 0;
int r = nums.length - 1;
int[] res = new int[nums.length];
int j = nums.length - 1;
while(l <= r){
if(nums[l] * nums[l] > nums[r] * nums[r]){
res[j--] = nums[l] * nums[l++];
}else{
res[j--] = nums[r] * nums[r--];
}
}
return res;
}
}
- 反思: 可以使用暴力破解做出来,但是缺乏对题目的思考,没有想到双指针的方法,进一步理解并掌握吧
Leetcode209.长度最小的子数组
难度:中等
| 相关标签:数组、二分查找、前缀和、滑动窗口
-
题目: 给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的子数组[numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
-
思路: 滑动窗口也可以理解为双指针法的一种。窗口就是 满足其和 ≥ s 的长度最小的 连续子数组。窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
-
注意:
- 滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果
- 在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。
- 暴力破解时间复杂度为O( n 2 n^{2} n2),滑动窗口为O(n),
-
代码:
暴力破解
两个for循环,然后不断的寻找符合条件的子序列。这里不多说了,直接掌握滑动窗口的方法就行
双指针法(滑动窗口):
滑动窗口终止位置用for遍历,一直在移动;关键在于如何移动滑动窗口初始位置
import java.util.*;
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int i = 0; //窗口初始位置
int j = 0; //窗口结束位置
int result = Integer.MAX_VALUE;
int sum = 0; //子序列的数值之和
for(; j < nums.length; j++){
sum = sum + nums[j];
while(sum >= target){
int sub = j - i + 1; // 子数组长度
result = Math.min(result, sub);
sum = sum - nums[i];
i++;
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
- 反思: 一般采用双指针的方法,可以将两个for循环解决的问题,简化为一个for循环解决的问题
Leetcode59.螺旋矩阵II
难度:中等
| 相关标签:数组、矩阵、模拟
-
题目:
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 -
思路: 模拟顺时针画矩阵的过程:填充上行从左到右 -> 填充右列从上到下 -> 填充下行从右到左 ->填充左列从下到上
由外向内一圈一圈这么画下去。 -
注意: 一定要坚持循环不变量原则,左闭右开。别忘记判断n 为奇数时,单独处理矩阵中心的值
-
代码:
class Solution {
public int[][] generateMatrix(int n) {
int[][] nums = new int[n][n];
int startX = 0, startY = 0; // 每一圈的起始点,初始状态nums[0][0]
int offset = 1;
int count = 1; // 矩阵中需要填写的数字
int loop = 1; // 记录当前的圈数
int i, j; // j 代表列, i 代表行;
while(loop <= n/2){
// 上行
for(j = 0; j < n-offset; j++){
nums[startX][j] = count;
count++;
}
// 右列
for(i = 0; i < n-offset; i++){
nums[i][j] = count;
count++;
}
// 下行
for(; j > startY; j--){
nums[i][j] = count;
count++;
}
// 左列
for(; i > startX; i--){
nums[i][j] = count;
count++;
}
startX++;
startY++;
offset++;
loop++;
}
// !!!一定要记得判断奇数的情况
if (n % 2 == 1) { // n 为奇数时,单独处理矩阵中心的值
nums[startX][startY] = count;
}
return nums;
}
}
- 反思: 一开始是没有思路的感觉很晕,后面看了讲解视频,要把问题拆解,仔细领会。看完后又去做的这道题,最后还是把奇数的情况遗忘了,运行出错才意识到问题。
总结:
- 知识点:
- 数组是存放在连续内存空间上的相同类型数据的集合
- 数组下标都是从0开始的
- 一维数组内存空间的地址是连续的
- 那么二维数组在内存的空间地址是连续的么?Java的二维数组在内存中不是 3*4 的连续地址空间,而是四条连续的地址空间组成