977. 有序数组
参考文章:
参考视频:
解题思路:
解法1:暴力解法,第一步将数组内元素遍历平方,第二步将数组内元素排序。
for(int i=0;i<nums.length;i++){
nums[i]*=nums[i];
}
Arrays.sort(nums);
return nums;
时间复杂度:O(n + nlog n)
解法2:双指针解法,左指针指向数组第一个元素,右指针指向数组最后一个元素,由于是升序排序,所以元素平方后较大的数会在数组的两头,通过左右指针指向的元素平方进行比较,平方后较大的元素从后往前存入创建的新数组中。
int left=0,right=nums.length-1;
int[] result = new int[nums.length];
int i=nums.length-1;
while(i>=0){
if(nums[left]*nums[left]>nums[right]*nums[right]){
result[i]=nums[left]*nums[left];
left++;
i--;
}else if(nums[right]*nums[right]>=nums[left]*nums[left]){
result[i]=nums[right]*nums[right];
right--;
i--;
}
}
return result;
时间复杂度:O(n)
209.长度最小的有序数组
参考文章:
参考视频:
解法1:暴力解法,通过两层for循环来寻找长度最小的子数组,后面力扣更新了数据,暴力解法已经超时了。
时间复杂度:O(n ^2)
解法2:滑动窗口(推荐):
在本题中实现滑动窗口,主要确定如下三点:
- 窗口内是什么?
- 如何移动窗口的起始位置?
- 如何移动窗口的结束位置?
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
解题的关键在于 窗口的起始位置如何移动,如图所示:
可以发现滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。
int i=0,j=0;
int min=Integer.MAX_VALUE;
int sum=0;
while(j<nums.length){
sum+=nums[j];
while(sum>=target){
min = Math.min(min, j - i + 1);
sum-=nums[i];
i++;
}
j++;
}
return min==Integer.MAX_VALUE?0:min;
时间复杂度: O(n)
59.螺旋矩阵II
参考文章:
参考视频:
解法:二分法,正确的二分法一定要坚持循环不变量原则,我在这里统一使用左闭右开原则。
图示:
这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。
这也是坚持了每条边左闭右开的原则。
注意对于n为奇数时最后一个元素要做单独处理。
int[][] nums = new int[n][n];
int i = 0;
int k = 1;
int index = 1;
int x = 0, y = 0, z = 0;
while (i < n / 2) {
x=z;
y=z;
for (y = z; y < n - k; y++) {
nums[x][y] = index++;
}
for (x = z; x < n - k; x++) {
nums[x][y] = index++;
}
for (; y > z; y--) {
nums[x][y] = index++;
}
for (; x > z; x--) {
nums[x][y] = index++;
}
z++;
k++;
i++;
}
if (n % 2 != 0) {
nums[n / 2][n / 2] = index;
}
return nums;
时间复杂度: O(n^2)