相关题目
977.有序数组的平方 <->力扣链接
209.长度最小的子数组 <->力扣链接
59.螺旋矩阵II <->力扣链接
解题过程
977.有序数组的平方
自己的解题思路
拿到这道题后,首先想到使用暴力解法,每个数据平方后在进行排序,代码如下
public static int[] sortedSquares(int[] nums) {
for (int i = 0; i < nums.length; i++) {
nums[i] = nums[i] * nums[i];
}
//排序
for (int i = 1; i < nums.length; i++) {
for (int j = 0; j < nums.length - 1; j++) {
if (nums[j] > nums[j + 1]) {//从小到大排序
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
return nums;
}
时间复杂度为O(n^2),题目中进阶版要求;请你设计时间复杂度为 O(n) 的算法解决本问题
如何实现呢?参考卡哥解答,总结如下:其实本题主要想考察双指针的应用,所以可是使用双指针解题。
由于**本题没有要求在原数组上进行处理,因此可是使用空间换时间,**本题中给出的原数组为有序数组,但会包含负数,
因此数组中各个元素的平方最大的值肯定在为两端的某一个,所以可定义两个指针分别指向数组头尾部,
开辟一个新的数组与原数组长度相同,由后向前遍历存储原数组剩余元素中平方最大的值。
实现代码如下
public static int[] sortedSquares(int[] nums) {
int[] res = new int[nums.length];
int left = 0;
int right = nums.length - 1;
int index = nums.length - 1;
while (left <= right) {
if (left == right) {
res[index] = nums[left] * nums[left];
}
if (nums[left] * nums[left] > nums[right] * nums[right]) {
res[index--] = nums[left] * nums[left];
left++;
} else {
res[index--] = nums[right] * nums[right];
right--;
}
}
return res;
}
总结:双指针在面试中的考题有很多,话不多说,继续练习
209.长度最小的子数组
这个题之前在新东方面试中考察过,因此印象比较深刻
自己的解题思路:可总结为历经坎坷
第一次尝试:使用双指针解题,设置快慢指针和求和的sum值,初始化为0,当sum值小于目标值时,fast加一,并将fast位置出的值加到sum中,当sum值大于等于目标值时,sum值减去慢指针所指向的位置值,慢指针加一
但如何记录子数组长度呢,使用fast-slow+1表示,
但这种情况只适用于最小长度数组处于数组末尾的情况,当最小长度处在数组之间怎么处理呢,这时我进行了
第二次尝试:另外定义一个数据介绍子数组长度最小值,,如图所示就在自以为可以的时候又出现了其他场景,我一个措手不及,直接凑答案
完整代码如下:
public static int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int fast = 0;
int slow = 0;
int len = 0;
int numSum=0;
int res = nums.length;
//求数组所有元素之和
for (int i = 0; i < nums.length; i++) {
numSum+=nums[i];
}
//数组所有元素之和小于目标值时,说明数组中不存在对应的最小序列
if(numSum < target){
return 0;
}
//数组所有元素之和等于目标值时,说明数组中所有元素构成了最小序列
else if(numSum == target){
return nums.length;
}
//其他场景
for (; fast < nums.length; fast++) {
sum += nums[fast];
while (sum >= target) {
len = fast-slow+1;
res = Math.min(res,len);
sum -= nums[slow++];
}
}
return res;
}
随想录相关解释
public int minSubArrayLen(int s, int[] nums) {
int left = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= s) {
result = Math.min(result, right - left + 1);
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
搜嘎,原来特殊情处理起来只需简单的一步,学费了
59.螺旋矩阵II
看到这个题目呢,其实早已打了退堂鼓,我这心里及其不健康的。算了,自己也没啥思路,直接看答案吧
卡哥解题思路
感觉学费了,自己动手一试,哎,有了!!!
public static int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int startX = 0;
int startY = 0;//标记每一圈的起始位置
int i = 0;
int j = 0;//标记行和列下标
int offset = 1;//标记每一圈的每一步的最后一步与边界的距离
int loop = 1;//记录当前圈数
int count = 1;//数组中写入的数值
while (loop <= n / 2) {
//从左到右,i不变,j递增
for (j = startY; j < n - offset; j++) {
//这里为什么要使用res[startX][j]而不是使用res[i][j]呢?因为startX和startY标记每一圈的起始位置,如果使用后者,一圈下来i和j的值都会从0开始,所以会出现错误如下图
res[startX][j] = count++;
}
//从上到下,j不变,i递增
for (i = startX; i < n - offset; i++) {
res[i][j] = count++;
}
//从右到左,i不变,j递减
for (; j > startY; j--) {
res[i][j] = count++;
}
//从下到上,j不变,i递减
for (; i > startX; i--) {
res[i][j] = count++;
}
startX++;
startY++;
offset++;
loop++;
}
//如果n为奇数,需要对中间点做特殊处理,即n^2需要做特殊处理
if (n % 2 == 1) {
res[startX][startY] = count;
}
return res;
}
总结:
难点在于
- 四个处理过程中i和j的初始值,即以下代码中for循环中i和j的初始化
for (j = startY; j < n - offset; j++) {
res[startX][j] = count++;
}
//从上到下,j不变,i递增
for (i = startX; i < n - offset; i++) {
res[i][j] = count++;
}
这是因为:startX和startY标记每一圈的起始位置,而四个for循环过程刚好是处理一圈,所以i和j的初始化分别为startX和startY
- 从左到右遍历时,for循环中res[startX][j] = count++;这里为什么要使用res[startX][j]而不是使用res[i][j]呢??
·······因为startX和startY标记每一圈的起始位置,如果使用后者,一圈下来i和j的值都会从0开始,所以会出现错误如下图
告诫自己:遇题不要慌,再难再繁琐的题都需要我静下心来慢慢破解,总会被解决的!!!加油吧,少年