Leetcode 977.有序数组的平方
题目链接:977. 有序数组的平方 - 力扣(LeetCode)
个人思考:
看到这个题目,想到了可能会使用到双指针的操作,但一直想的是在原数组上进行操作,然后排序,这样的话在交换元素的时候就会很麻烦,没有想到重新申请一个新数组,然后双指针思想对数组进行排序。
暴力解法
思路:暴力解法的思路比较简单,就是遍历数组,得到平方后的数组,然后再对平方后的数组进行排序。
代码:
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;
}
}
时间复杂度:O(n + nlogn) 空间复杂度:O(1)
1.java.long.Math类里面的方法pow方法
![]()
2.Arrays.sort()方法对数组进行从小到大的排序。
双指针解法
思路:原数组是有序的,因此平方之后也是有“有序”的特点在的,不过左边的负数平方后可能成为新数组中的最大值,因此新数组中元素的最大值要么出现在原数组的左边,要么出现在原数组的右边,不可能出现在中间。
图源:双指针思路演示
代码:
class Solution {
public int[] sortedSquares(int[] nums) {
//双指针解法
int left = 0, right = nums.length - 1;
int[] res = new int[nums.length];//创建一个新数组,保存最终结果
int k = nums.length - 1;//从后往前依次存储
while(left <= right){
if(nums[left] * nums[left] < nums[right] * nums[right]){
res[k --] = nums[right] * nums[right];
right --;
}else{
res[k --] = nums[left] * nums[left];
left ++;
}
}
return res;
}
}
时间复杂度:O(n) 空间复杂度:O(n)
注意:循环条件是left <= right 不是left < right,否则会漏掉一个元素(新数组中最小的元素)
Leetcode 209.长度最小的子数组
题目链接:209. 长度最小的子数组 - 力扣(LeetCode)
暴力解法
思路:这道题目暴力解法的思路就是找出这个数组的所有子序列,然后在所有子序列中找出长度最小的且值大于等于s的子数组序列。
代码:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int resLen = Integer.MAX_VALUE;//记录最终的结果
int sum = 0;
for(int i = 0; i < nums.length; i ++){//i记录子数组序列的起始位置
for(int j = i; j < nums.length; j ++){//j记录子数组序列的终止位置
sum += nums[j];
if(sum >= target){
resLen = Math.min(resLen, j - i + 1);
break;//因为要找最小的,所以找到后break就行,不用累加后面的了
}
}
sum = 0;//记得处理一个子序列后,sum要初始化为0
}
return resLen == Integer.MAX_VALUE ? 0 : resLen;
}
}
时间复杂度:O(n2) 空间复杂度:O(1)
注意点:
1.一个子序列累加之后,开始尝试新的子序列的时候,记得sum初始化为0。(最开始写的时候,忘记了,结果一直在累加,导致程序出错。)
2.题目要求找长度最小的,因此找到之后直接break,不用累加后面的了。
3.暴力解法目前在leetcode上面提交已经超时了。
运行几个简单测试用例通过
提交显示超时
滑动窗口解法
暴力解法中使用两个for循环来控制子数组序列的起始位置(外层for循环i)和终止位置(内层for循环j)。那么有没有什么方法能够使用一层for循环来实现呢?答案:滑动窗口
只使用一层for循环,那应该用它来记录子数组序列的起始位置还是终止位置呢?
- 起始位置?如果记录起始位置,那终止位置怎么记,仿佛又回到了暴力解法。
- 终止位置?如果使用循环记录终止位置,那么起始位置怎么记,可以依赖target的值来动态确定。
有个数组[2, 3, 1, 2, 4, 3],寻找target为7的子数组长度。
代码:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int resLen = Integer.MAX_VALUE;//记录最终的结果
int i = 0, sum = 0;
for(int j = 0; j < nums.length; j ++){//j用来记录子数组的终止位置
sum += nums[j];
while( sum >= target){
resLen = Math.min(resLen, j - i + 1);//记录当前满足>=target条件的子数组长度
sum -= nums[i];//缩小区间范围
i ++;//窗口滑动
}
}
return resLen == Integer.MAX_VALUE ? 0 : resLen;
}
}
时间复杂度:O(n) 空间复杂度:O(1)
注意:先缩小区间范围sum -= nums[i],再 i ++,两个顺序不要弄反了。
Leetcode 59.螺旋矩阵II
题目链接:59. 螺旋矩阵 II - 力扣(LeetCode)
思路:
这道题目是数组模拟题目,主要就是再循环一圈又一圈的过程中,区间的左右边界上的处理,涉及数组区间问题,要考虑到底是使用左闭右开,还是左闭右闭,保持统一。
代码:
class Solution {
public int[][] generateMatrix(int n) {
//数组模拟题
int[][] res = new int[n][n];
int loop = 1;//圈的个数
int num = 1;//记录填入矩阵的数
int i , j ;
int startx = 0, starty = 0;//存储每一圈开始的起始位置
int offset = 1;//控制每一条边的遍历长度,每遍历一圈,右边界向内收缩一位
while(loop <= n / 2){
i = startx;
j = starty;
//从左到右(左闭右开)
for(; j < n - offset; j ++ ){
res[startx][j] = num ++;
}
//从上到下
for(;i < n - offset ; i ++){
res[i][j] = num ++;//此时j = n - 1;
}
//从右到左
for(;j > starty; j -- ){
res[i][j] = num ++;
}
//从下到上
for(; i > startx; i--){
res[i][j] = num ++;
}
startx ++;
starty ++;
offset ++;
loop ++;
}
//最后处理最中心的元素(n为奇数的情况下)
if( n % 2 != 0){
res[n / 2][n / 2] = num ++;
}
return res;
}
}
时间复杂度:O(n2) 空间复杂度:O(1)