上次的博客,我们记录数组中常见的算法题目,今天我们来讨论另外三种常见的算法题型: 分别是 有序数组平方,长度最小的子数组和螺旋矩阵。
其LeetCode对应题目分别是:有序数组的平方,长度最小的子数组,59. 螺旋矩阵 II
有序数组的平方
这道题目的可以暴力来做,但是如果达到最优时间复杂度,可以使用双指针的方法。
定义两个指针left和right,和我们二分法的时候一样,边界条件也是类似,关键点就是二分法的条件发生了改变。if(nums[left]*nums[left]>=nums[right]*nums[right])和<这两种情况,那种条件大就把谁的值赋给result,同时result指针从大向小移动。
下面是我的代码实现并且了注释,其时间复杂度O(N),空间复杂度O(N)。
lass Solution {
public int[] sortedSquares(int[] nums) {
//首先要求时间复杂度O(N)应该是数组的原地移动,要求非递减顺序
//这个可以理解为target等于所有数组元素的移动移动不再是fast元素了而是从两头进行移动也就是因为
//从两头向中间进行移动移动
int left=0;
int right=nums.length-1;
int [] result=new int[nums.length];
int rresult=nums.length-1;
while(left<=right){
if(nums[left]*nums[left]>=nums[right]*nums[right]){//当左指针的数据平方大于等于右指针的数据的平方
result[rresult]=nums[left]*nums[left];
left=left+1;
}
else{
//当左指针的数据平方大于等于右指针的数据的平方
result[rresult]=nums[right]*nums[right];
right=right-1;
}
rresult--; //我们将数据放到result,result索引左移
}
return result;
}
}
运行结果:
长度最小子数组
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
- 输入:s = 7, nums = [2,3,1,2,4,3]
- 输出:2
- 解释:子数组 [4,3] 是该条件下的长度最小的子数组。
提示:
- 1 <= target <= 10^9
- 1 <= nums.length <= 10^5
- 1 <= nums[i] <= 10^5
这道题目如果不是暴力解法的话,需要使用滑动窗口的解法,前后两个指针进行扫描,实现最快的检索。
首先我先写一下我的暴力解法代码,时间超时。
int sub_result;
for(int i=0;i<nums.length;i++){
//对每一个元素进行遍历
sub_result=0;
for(int j=i;j<nums.length;j++){
//
sub_result=+sub_result+nums[j];
if(sub_result>=target){
if(sub_length>j-i+1){
sub_length=j-i+1;
break;
}
}
}
}
return sub_length==Integer.MAX_VALUE?0:sub_length;
下面是滑动窗口的代码实现
int left=0;
int result=0;
int sublength=Integer.MAX_VALUE;
for(int right=0;right<nums.length;right++){
result+=nums[right];
while(result>=target){
sublength=Math.min(sublength,right-left+1);
result=result-nums[left];
left++;
}
}
return sublength == Integer.MAX_VALUE ? 0 : sublength;
其核心点在于 result专门存储结果,当result的值大于target的时候,left指针移动移动到result的值小于target为止,这时候right指针进行移动。两者互相切换,时间复杂度O(N)空间复杂度O(1)。 这里的result>=target记住不要写错,并且是while循环,需要left指针一直左移直到result<target而非移动一次.
运行结果截图:
螺旋矩阵
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
这道题目是一道模拟题目,需要对边界条件有很好的把控,不要很容易写错。这里需要注意你需要确定你使用的是什么区间,一直使用下去。
//一道经典的模拟题目
int loop=0;//循环次数
int start=0;//每次的起始点
int [][]result=new int[n][n];//结果矩阵
int i,j;// i代表行,j代表列
int count=1;//定义开始时候要填的值,刚开始我们从1开始执行
while(loop++<n/2){
for(j=start;j<n-loop;j++){
result[start][j]=count++;
}
for(i=start;i<n-loop;i++){
//
result[i][j]=count++;
}
for(;j>=loop;j--){
result[i][j]=count++;
}
for(;i>=loop;i--){
result[i][j]=count++;
}
start++;
}
//如果n是奇数那么中间会有一个值,需要我们单独处理
if(n%2==1){
result[start][start]=count;
}
return result;
}
我们着重说一下模拟的四种情况,最上面一行向右运动->//start 行不动,对于列进行移动,移动次数是n-loop次,接下来是列不同,也就是j不动,行向下移动,移动次数也是n-loop。接下来向左移动,这时候也是j运动,这时候J的运动次数不再是n-loop,而是大于等于loop。因为我们是一个螺旋。最后向上运动,同样也是大于等于loop,不过i是不断减小的。
最后一点就是如果是层数是奇数个,中间位置的数字很有可能取不到,因此我们一般直接填入。
总结
数组方面做的题目常考的面试算法题目主要是这五个种题型,LeetCode上面也有大量的变种,大家可以去刷一下题目。最后祝愿大家算法全部AK。