双指针算法 + 螺旋矩阵(LeetCode刷题!!!)
跟着carl哥的第二天
今天仔细学了双指针算法,以及推演了螺旋矩阵。通过这篇文章可以让你更快认识到双指针算法的魅力,以及螺旋矩阵的基本做法。
双指针算法
先看第一道题
leetcode977.有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100],
排序后,数组变为 [0,1,9,16,100]
示例2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
这道题先设想一下,如果双指针的话该怎么做,怎么样找出数组中的最大值,然后放在新数组的最后位,只要解决第一步后面就都迎刃而解了!
答案:::
public class test01 {
//定义输入输出
public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
//读入一行,并按照空格拆分
String s = in.readLine();
String[] str = s.split(",");
int n = str.length;
//转为int数组
int[] nums = new int[n];
for (int i = 0; i < n; i ++) {
nums[i] = Integer.parseInt(str[i]);
}
int[] arr = sortedSquares(nums);
out.write(Arrays.toString(arr));
out.flush();
out.close();
//System.out.println(Arrays.toString(arr));
}
private static int[] sortedSquares(int[] nums) {
int left = 0;
int right = nums.length - 1;
int[] result = new int[nums.length];
int index = nums.length - 1;
while(index != -1) {
//左边的平方大于右边的平方
if (nums[left] * nums[left] >= nums[right] * nums[right]) {
result[index --] = nums[left] * nums[left];
left ++;
//右边的平方小于左边的平方
} else {
result[index --] = nums[right] * nums[right];
right --;
}
}
return result;
}
}
通过指针指定左右两个边界,然后判断两边界的平方谁大即可解。
再看第二道题
209.长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例 :
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
用双指针算法来说就是:
你要怎么去找到任何一个子数组,子数组的范围跟里面的和该怎么定义。
找到任何一个子数组的话:我们需要去确定左边界跟右边界(又是两指针)
也就是说左边界跟右边界又该怎么去移动呢?
我们是通过子数组里边的和跟target去判断来移动左右两指针的。
左边界的移动:如果当前子数组里边的和大于target了,窗口就要向前移动了(也就是该缩小了)
右边界的移动:窗口的结束位置是遍历数组的指针,也就是for循环里的索引
答案:
public class test02 {
//定义输入输出
public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
//读入一个数字,默认读入String 需要转为int
Integer target = Integer.parseInt(in.readLine());
//读入一行,并按照空格拆分
String s = in.readLine();
String[] str = s.split(" ");
int n = str.length;
//转为int数组
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = Integer.parseInt(str[i]);
}
int count = minSubArrayLen(nums, target);
out.write(Integer.toString(count));
out.flush();
out.close();
}
private static int minSubArrayLen(int[] nums, Integer target) {
int index = 0; //左边界
int sum = 0; //子数组的和
int result = Integer.MAX_VALUE;
for (int i = 0; i < nums.length; i ++) { //i为右边界
sum += nums[i];
// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
//例子[1,1,1,1,100] target=100
while (sum >= target) {
//不断遍历,直到找出最小值
result = Math.min(result, i - index + 1);
//当子数组的值大于target时,我们需要让左指针往前走,来检查还能否符合条件
sum -= nums[index ++];
}
}
//如果没有找到合适的子数组,返回0
return result == Integer.MAX_VALUE ? 0 : result;
}
}
最后高频面试题:螺旋矩阵
leetcode59.螺旋矩阵II
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例:
- 输入: 3
- 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
思路:
一开始我也脑子是蒙的,然后我就自己推演了一下,用实例去推演了一圈,因为这种题应该是有规律的。
假如 n=4 且我们只看最外圈
// 0 1 2 3
//0 [ 1, 2, 3, 4]
//1 [12,13,14, 5]
//2 [11,16,15, 6]
//3 [10, 9, 8, 7]
//设一个值,来给矩阵赋值
int count = 1;
//设置一个二位矩阵来存储螺旋矩阵
int[][] res = new int[4][4];
//设置起点的坐标
int i = 0;
int j = 0;
//因为我们要循环四条边,所以我们需要找一个规律
//使得四条边的规则是一样的
//这里我们设置的是 4个for: 相同之处在于包含起点但不包含终点(终点是下条边的起点)
//第一条边:1->3
for (j = 0; j < n - 1; j ++)
res[0][j] = count ++;
//第二条边:4->6
for (i = 0; i < n - 1; i ++)
res[i][j] = count ++;
//第三条边:7->9
for (; j > 0; j --)
res[i][j] = count ++;
//第四条边:10->12
for (; i > 0; i --)
res[i][j] = count ++;
//如果是n=奇数,那最中间的那个位置就没有值,所以我们设置一个mid
//让累加到最后的count赋值给最终的位置
int mid = n / 2;
res[mid][mid] = count;*/
然后就很简单了,把里面的固定值换成符合题目的变量,让变量去代替固定值,这样就能把整个矩阵画出来了
答案:
public class test03 {
public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
int n = Integer.parseInt(in.readLine());
int[][] result = new int[n][n];
result = generateMatrix(n);
out.write(Arrays.toString(result));
}
private static int[][] generateMatrix(int n) {
int[][] result = new int[n][n];
int count = 1;
int startx = 0; //起点的横坐标
int starty = 0; //起点的纵坐标
//因为n=4 就只有两圈,所以就是n/2
int loop = n / 2; //圈数
int mid = n / 2;
int offset = 1; //随之圈子的缩小,offset增加,也就是遍历每条边的长度
while(loop -- > 0) {
//记住这里定义的是下面4个for的全局变量
int i = startx;
int j = starty;
for (j = starty; j < n - offset; j ++) {
result[startx][j] = count ++;
}
for (i = startx; i < n - offset; i ++) {
result[i][j] = count ++;
}
for (; j > starty; j --) {
result[i][j] = count ++;
}
for (; i > startx; i --) {
result[i][j] = count ++;
}
startx ++; //随之圈数增加 起始坐标也会越来越往中间
starty ++;
offset ++;
}
if (n % 2 == 1) {
result[mid][mid] = count;
}
return result;
}
}
自我总结
基本有了双指针算法的思想了~~ 大概吧应该吧。
然后学会高频面试题还是挺开心的嘿嘿
大概就是这样,大家懂了吗 有什么不懂的评论区评论或者私信我吧!!