有序数组的平方--双指针
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
文章链接:代码随想录
暴力解法:
将所有元素平方,然后排序,即可得出
时间复杂度:O(nlogn)
public int[] sortedSquares(int[] nums) {
for (int i = 0; i < nums.length; i++) {
nums[i] *= nums[i];
}
Arrays.sort(nums);
return nums;
}
双指针解法:
因为是一个递增数组且含有负数,平方后的数最大值不是在最左边就是在最右边,可以使用对撞双指针
可以创建一个相同大小的新数组,左右指针相互比较,较大的数放入数组空闲位置的最后一位,且下标往内收,不断重复该过程,直至left>right
时间复杂度:O(n)
public int[] sortedSquares(int[] nums) {
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[left] >= nums[right] * nums[right]) {
res[index--] = lnum;
left++;
} else {
res[index--] = rnum;
right--;
}
}
return res;
}
长度最小的子数组--滑动窗口
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
文章链接:代码随想录
滑动窗口:本质是满足了单调性,即左右指针只会往一个方向走且不会回头,收缩的本质即去掉不需要的元素。也就是做题我们可以先固定移动右指针,判断条件是否可以收缩左指针计算范围
滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)的暴力解法降为O(n)
暴力解法:
观察题目给出的数据范围:1<=nums.length<=10^5,如果用暴力解法两个for循环(O(n^2))可以得出题解,但是会超出数据范围达到10^10 (>10^8就算超时)
双指针--滑动窗口解法:
自己的想法
同向双指针,模仿两个for循环使得时间复杂度降低,快指针不断移动,直至左右范围内的和>=target时,记录当前窗口的长度,让右指针等于左指针,重复以上的操作,相当于每个下标都作为一次窗口的左端
时间复杂度:O(n)
public int minSubArrayLen(int target, int[] nums) {
int slow = 0;
int length = Integer.MAX_VALUE;
int sum = 0;
for (int fast = 0; fast < nums.length; fast++) {
sum += nums[fast];
if (sum >= target) {
length = Math.min(fast - slow + 1, length);
slow++;
sum = 0;
fast = slow - 1;
}
}
return length == Integer.MAX_VALUE ? 0 : length;
}
题解:
和上式的区别:不是尝试每个下标的区间最优解,而是让窗口保持在>=target的范围内不断收缩,以此得到最优解
时间复杂度:O(n)
public int minSubArrayLen(int target, int[] nums) {
int slow = 0;
int sum = 0;
int length = Integer.MAX_VALUE;
for (int fast = 0; fast < nums.length; fast++) {
sum+= nums[fast];
while (sum >= target) {
length = Math.min(length, fast - slow + 1);
sum -= nums[slow++];
}
}
return length == Integer.MAX_VALUE ? 0 : length;
}
疑惑
for里面嵌套着while,为什么时间复杂度却是O(n),而不是O(nlogn)?
看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)
我自己写的算双指针吗?我的右指针都会=左指针,就相当于每个下标都遍历一次,相当于重新来,直至左右指针范围里的和大于target,我不确定这个算不算
录友回答
什么是窗口,其实就是[slow,fast]这个闭区间,并对这个闭区间做计算,你这个其实就是窗口,只是每次都以slow为基准往前找,虽然也可以实现,但是走回头路了,因为每次都重新从slow往前叠加,你求区间和的动作不就重复了吗。
其实找到了一个比target大的区间,你只需要保持fast在原地,让slow往前找,slow每移动一步就把值从窗口中拿掉,这样就不用走回头路了。简单来说就是fast前面探路,slow在后面追。两个指针都不走回头路。
螺旋矩阵II
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
文章链接:代码随想录
模拟题:
坚持循环不变量原则,左闭右开,模拟转圈的过程
时间复杂度:O(n^2)
public int[][] generateMatrix(int n) {
int loop = 0; //控制循环次数(圈数)
int start = 0; //每次循环的开始点(start,start)
int count = 1; //填充数字
int[][] res = new int[n][n];
int i,j;
while (loop++ < n / 2) { //判断边界后,loop从1开始
//模拟上侧从左到右
for (j = start; j < n - loop; j++) {
res[start][j] = count++;
}
//模拟右侧从上到下
for (i = start; i < n - loop; i++) {
res[i][j] = count++;
}
//模拟下侧从右到左
for (; j >= loop; j--) {
res[i][j] = count++;
}
//模拟左侧从下到上
for (; i >= loop; i--) {
res[i][j] = count++;
}
start++;
}
//如果n为奇数,填充中间缺少的位置
if (n % 2 == 1) res[start][start] = count;
return res;
}
总结体悟
今天的数组题用到了双指针,其中双指针又分为对撞指针和同向指针,同向指针其中的一个应用方法就是滑动指针,我自己的思路虽然也算上滑动窗口,但是错在了每次都让fast从以slow为基准值往前叠加,反复去求区间和,走了回头路...刷到模拟题的时候错在了没有准守循环不变量原则,这也让我对这个原则有了明确的认识...今天是第二天,虽然平时也有事要干,但每天抽出点时间来学算法也算是我的一点乐趣,什么时候学都不算晚,坚持才是关键✊!!!