一,题977. 有序数组的平方(双指针法)
题目链接:
力扣
给你一个按 非递减顺序 排序的整数数组 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];
class Solution {
public int[] sortedSquares(int[] nums) {
int left=0;
int right=nums.length-1;
int k=nums.length-1;
int [] result=new int[nums.length];
while(left<=right)
{
if(nums[left]*nums[left]<nums[right]*nums[right])
{
result[k]=nums[right]*nums[right];
right--;
k--;
}
else
{
result[k]=nums[left]*nums[left];
left++;
k--;
}
}
return result;
}
}
其中
result[k]=nums[right]*nums[right];
right--;
k--;
可以简写为如下代码
result[k--]=nums[right]*nums[right--];
二,209.长度最小的子数组
题目链接:
力扣
- 时间复杂度:O(n)
- 空间复杂度:O(1)
在本题中实现滑动窗口,主要确定如下三点:
- 窗口内是什么?
- 如何移动窗口的起始位置?
- 如何移动窗口的结束位置?
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left=0;
int result =Integer.MAX_VALUE;
int sum=0;
for(int right=0;right<nums.length;right++)
{
sum+=nums[right];
while(sum>=target)
{
int length=right-left+1;
result = Math.min(result, length);
sum-=nums[left++];
}
}
return result ==Integer.MAX_VALUE? 0 : result;
}
}
Integer.MAX_VALUE表示int数据类型的最大取值数:2 147 483 647
Integer.MIN_VALUE表示int数据类型的最小取值数:-2 147 483 648
补充:
Integer.MAX_VALUE+1=Integer.MIN_VALUE因为:
Integer.MAX_VALUE的二进制是0111 1111 1111 1111 1111 1111 1111 1111
Integer.MIN_VALUE的二进制是 1000 0000 0000 0000 0000 0000 0000 00000111 1111 1111 1111 1111 1111 1111 1111+1=1000 0000 0000 0000 0000 0000 0000 0000
其中Integer.MAX_VALUE可以换成一个较大的值,如99999999。
最后一行不能删除,否则报错,分析一下这种情况:
此时永远不会满足 while(sum>=target),直接遍历完数组,不会执行while语句中的值,result的值还是之前默认的那个很大的数。而实际上没有找到满足的子数组result应该返回0。所以最后不能直接返回result,而是
return result ==Integer.MAX_VALUE? 0 : result;
以下三种写法都是等效的
result = Math.min(result, length);
result = (result<length)?result:length;
if(result>length) result=length;
最后,不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。像上面那种极端的情况下直接不进入到while中,只被操作一次,时间复杂度是 n,也就是O(n)。
三,59.螺旋矩阵II(注意保持左闭右开区间原则)
题目链接:力扣
本题依然是要坚持循环不变量原则。
模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
由外向内一圈一圈这么画下去。
class Solution {
public int[][] generateMatrix(int n) {
int [][]nums=new int[n][n];
int start=0;
int count=1;
int loop=0;
int i,j;
while(loop++<n/2)
{
for(j=start,i=start;j<n-loop;j++)
nums[i][j]=count++;
for(;i<n-loop;i++)
nums[i][j]=count++;
for(;j>=loop;j--)
nums[i][j]=count++;
for(;i>=loop;i--)
nums[i][j]=count++;
start++;
}
if(n%2==1)
{
nums[start][start]=count;
}
return nums;
}
}
注意: while(loop++<n/2)中的loop++不能放到循环末尾,也不能直接改成++loop,否则会报错;
可改为
while(++loop<=n/2)
也可以直接放在循环的第一行
while(loop<n/2)
{
loop++; /++loop;
.......
}
但是改为下面这样会报错
while(loop<=n/2)
{
++loop;
.....
}
加入输出语句,可以看出运行过程。可以看到多了一次循环,但是下标已经不对了,start变为了2,应该是nums[1][1]=9(即nums[start][start]=9)
正确的运行结果如下: