LeetCode通关:数组十七连,真是不简单

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝

int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。

// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。

for (int i = 0; i < len; i++) {

print(nums[i]);

}

💡 思路

暴力解法

暴力解法没什么好说的,和上道题类似,找到要删除的元素,把它后面的元素全部向前移动一位。

暴力解法

这里有两点需要注意:

  • 需要先定义变量 length 获取数组长度,因为后面我们的返回的数组长度是改变的

  • 每找到一个需要删除的值的时候,需要 i–,防止出现多个需要删除的值在一起的情况,然后漏删

代码如下:

public int removeElement(int[] nums, int val) {

int length = nums.length;

int i = 0;

for (; i < length; i++) {

if (nums[i] == val) {

for (int j = i; j < length - 1; j++) {

nums[j] = nums[j + 1];

}

//防止漏删

i–;

//数组长度减一

length–;

}

}

return length;

}

⏰ 时间复杂度:O(n²)。

双指针法

双指针法,是数组和链表题中非常常用的一种方法。

这道题用双指针法怎么解决呢?

定义两个指针,一个前,一个后。没有找到目标的时候front和after一起移动,找到目标的时候,after停下来,front接着移动,把front指向的值赋给after指向的值。

这样一来,双指针就通过一个循环完成了双循环完成的事情。

双指针法

代码如下:

public int removeElement(int[] nums, int val) {

//定义前后指针

int front = 0;

int after = 0;

for (; front < nums.length; front++) {

if (val != nums[front]) {

nums[after] = nums[front];

after++;

}

}

return after;

}

⏰ 时间复杂度:O(n)。

LeetCode26. 删除有序数组中的重复项


☕ 题目:27. 移除元素 (https://leetcode-cn.com/problems/remove-element/)

❓ 难度:简单

📕 描述:

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝

int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。

// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。

for (int i = 0; i < len; i++) {

print(nums[i]);

}

题目示例

💡 思路

趁着上一道题劲儿还没缓过来,赶紧做一道基本一样的巩固一下。

直接上代码:

public int removeDuplicates(int[] nums) {

int front = 1;

int after = 1;

for (; front < nums.length; front++) {

if (nums[front] != nums[front - 1]) {

nums[after] = nums[front];

after++;

}

}

return after;

}

⏰ 时间复杂度:O(n)。

LeetCode283. 移动零


☕ 题目:283. 移动零 (https://leetcode-cn.com/problems/move-zeroes/)

❓ 难度:简单

📕 描述:

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]

输出: [1,3,12,0,0]

说明:

  1. 必须在原数组上操作,不能拷贝额外的数组。

  2. 尽量减少操作次数

💡 思路

继续沿着上一道题的思路。

  • 第一步:我们可以把为零的元素先给它删掉,怎么删呢?就是LeetCode26的两个指针的删除方式

  • 第二步:但是我们这是将零移动到末尾,怎么办呢?我们把通过移动方式删除,导致数组末尾的坑用零填上就行了。

移动零

代码如下:

/**

  • @return void

  • @Description: 283. 移动零

  • @author 三分恶

  • @date 2021/7/30 7:44

*/

public void moveZeroes(int[] nums) {

int after = 0;

int front = 0;

//移动元素

for (; front < nums.length; front++) {

if (nums[front] != 0) {

nums[after] = nums[front];

after++;

}

}

//将末尾元素置为0

for (; after < nums.length; after++) {

nums[after] = 0;

}

}

⏰ 时间复杂度:O(n)。

LeetCode977. 有序数组的平方


☕ 题目:977. 有序数组的平方 (https://leetcode-cn.com/problems/squares-of-a-sorted-array/)

❓ 难度:简单

📕 描述:

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

题目示例

💡 思路

暴力排序法

这道题一看,最直观的做法是什么呢?

先求数字平方的数组,然后再把新数组排序。

代码也好写:

/**

  • @return int[]

  • @Description: 977. 有序数组的平方-暴力法

  • @author 三分恶

  • @date 2021/7/30 8:03

*/

public int[] sortedSquares(int[] nums) {

for (int i = 0; i < nums.length; i++) {

nums[i] *= nums[i];

}

//快排,时间复杂度O(nlogn)

Arrays.sort(nums);

return nums;

}

⏰ 时间复杂度:遍历时间复杂度O(n),快排时间复杂度O(nlogn),所以时间复杂度O(n+nlogn)。

💡 思路

双指针法

我们连写几道双指针了,这道题能不能用双指针实现呢?

我们分析一下,这个数组在取平方之前,是有序的,那么它绝对值最大的数一定是在两端的。

所以我们可以定义两个指针,一个指向最左端,一个指向最右端,比较两者平方的大小,大的平方放入结果数组,并移动指针。

有序数组的平方

代码如下:

/**

  • @return int[]

  • @Description: 977. 有序数组的平方-双指针法

  • @author 三分恶

  • @date 2021/7/30 8:29

*/

public int[] sortedSquares(int[] nums) {

int left = 0;

int right = nums.length - 1;

int[] result = new int[nums.length];

int r = nums.length - 1;

while (left <= right) {

int leftRes = nums[left] * nums[left];

int rightRes = nums[right] * nums[right];

//右边大

if (leftRes <= rightRes) {

result[r] = rightRes;

right–;

} else {

//左边大

result[r] = leftRes;

left++;

}

r–;

}

return result;

}

⏰ 时间复杂度:O(n)。

两数之和

======================================================================

LeetCode1. 两数之和


☕ 题目:1. 两数之和 (https://leetcode-cn.com/problems/two-sum/)

❓ 难度:简单

📕 描述:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

题目示例

💡 思路:

暴力解法

上来我们先来个最简单的暴力解法,大家应该都知道冒泡排序吧,类似的两层循环。

两层循环

代码写起来也很简单:

public int[] twoSum(int[] nums, int target) {

int[] result = new int[2];

for (int i = 0; i < nums.length; i++) {

for (int j = i + 1; j < nums.length; j++) {

if (nums[i] + nums[j] == target) {

result[0] = i;

result[1] = j;

return result;

}

}

}

return result;

}

⏰ 时间复杂度:看到这个双循环,就知道时间复杂度O(n²)。

哈希辅助法

时间复杂度O(n²)多少有点过了,这道题的重点是两个元素相加之和的判断。

我们可以用一个Hash集合把元素存起来,这样一来遍历一遍就够了,例如目标和9,当前元素2,只需要判断集合里是否有元素7就行了。

public int[] twoSum(int[] nums, int target) {

HashMap<Integer, Integer> map = new HashMap<>(16);

int[] result = new int[2];

for (int i = 0; i < nums.length; i++) {

//目标元素

int goal = target - nums[i];

if (map.containsKey(goal)) {

result[0] = map.get(goal);

result[1] = i;

return result;

}

//将数组值作为key,下标作为value

map.put(nums[i], i);

}

return result;

}

⏰ 时间复杂度:从Hash查询和取值时间复杂度都是O(1),所以整体时间复杂度是O(1)。

LeetCode15. 三数之和


☕ 题目:15. 三数之和 (https://leetcode-cn.com/problems/3sum/)

❓ 难度:简单

📕 描述:

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

题目示例

💡 思路:

哈希法

做完两数之和以后,我们首先想到的就是哈希法。

两层循环,取到a,b,再通过 0-(a+b) 来确定c。

但是这里还有一个问题,答案中不可以包含重复的三元组。

所以,我们还要想办法去掉Hash里的重复元素。

可以加入一个约束,第三个数的索引大于第二个数才存入。

public List<List> threeSum(int[] nums) {

List<List> result = new ArrayList<>(16);

if (nums.length < 3) {

return result;

}

//排序

Arrays.sort(nums);

HashMap<Integer, Integer> map = new HashMap<>();

//将元素存入hash表

for (int i = 0; i < nums.length; i++) {

map.put(nums[i], i);

}

Integer c;

int target = 0;

for (int a = 0; a < nums.length; a++) {

target = -nums[a];

//去重

if (a > 0 && nums[a] == nums[a - 1]) {

continue;

}

for (int b = a + 1; b < nums.length; b++) {

//去重

if (b > a + 1 && nums[b] == nums[b - 1]) {

continue;

}

//从hash表获取c

if ((c = map.get(target - nums[b])) != null) {

//c下彪必须大于b

if (c > b) {

result.add(new ArrayList<>(Arrays.asList(nums[a], nums[b], nums[c])));

} else {

break;

}

}

}

}

return result;

}

⏰ 时间复杂度:双循环,O(n²)。

虽然这么也写出来了,但是,说实话,很难写出没有问题的代码。

我们写了这么多双指针,那么有没有可能用双指针的方式呢?

双指针法

首先对数组进行排序,然后遍历数组。

然后再在当前节点后面取左右指针,判断左右指针的值是否等于0-nums[i],然后分别左右移动。

怎么去重呢?

满足条件时,看左指针的值是否和前一个位置相等,右指针的值是否和和它后一个位置的值相等。

双指针法

代码如下:

public static List<List> threeSum(int[] nums) {

List<List> result = new ArrayList<>(16);

if (nums.length < 3) {

return result;

}

//排序

Arrays.sort(nums);

//遍历

for (int i = 0; i < nums.length-2; i++) {

//如果当前元素大于0,三数之和一定大于0

if (nums[i] > 0) {

break;

}

int left = i + 1;

int right = nums.length - 1;

int count = 0 - nums[i];

//去重

if (i > 0 && nums[i] == nums[i - 1]) {

continue;

}

while (left < right) {

int sum = nums[i] + nums[left] + nums[right];

if (sum == 0) {

result.add(new ArrayList<>(Arrays.asList(nums[i], nums[left], nums[right])));

//去重,注意去重逻辑要放在找到第一个三元组之后

while (left < right && nums[left] == nums[left + 1]) {

left++;

}

while (left < right && nums[right] == nums[right - 1]) {

right–;

}

//找到结果,双指针同时移动

left++;

right–;

} else if (sum < 0) {

//左指针右移

left++;

} else if (sum > 0) {

//右指针左移

right–;

}

}

}

return result;

}

⏰ 时间复杂度:O(n²)

LeetCode18. 四数之和


☕ 题目:18. 四数之和 (https://leetcode-cn.com/problems/4sum/)

❓ 难度:简单

📕 描述:

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:答案中不可以包含重复的四元组。

题目示例

💡 思路:

我们延续三数之和的思路,在三数之和外面再套一层循环。

public List<List> fourSum(int[] nums, int target) {

List<List> result = new ArrayList<>(16);

if (nums.length < 4) {

return result;

}

//排序

Arrays.sort(nums);

for (int i = 0; i < nums.length - 3; i++) {

//去重

if (i > 0 && nums[i] == nums[i - 1]) {

continue;

}

for (int j = i + 1; j < nums.length - 2; j++) {

//去重

if (j > i + 1 && nums[j] == nums[j - 1]) {

continue;

}

int left = j + 1;

int right = nums.length - 1;

while (left < right) {

int sum = nums[i] + nums[j] + nums[left] + nums[right];

if (sum == target) {

result.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[left], nums[right])));

//去重

while (left < right && nums[left] == nums[left + 1]) {

left++;

}

while (left < right && nums[right] == nums[right - 1]) {

right–;

}

left++;

right–;

} else if (sum > target) {

right–;

} else if (sum < target) {

left++;

}

}

}

}

return result;

}

⏰ 时间复杂度:O(n³)

滑动窗口

======================================================================

LeetCode209. 长度最小的子数组


☕ 题目:209. 长度最小的子数组(https://leetcode-cn.com/problems/minimum-size-subarray-sum/)

❓ 难度:中等

📕 描述:

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

题目示例

💡 思路

这道题是一道经典的滑动窗口问题[4]。

  • 使用start、end指针,分别表示滑动窗口的起始、终止位置

  • 移动end指针,扩大窗口,直到子数组达到目标值target

  • 移动start指针,缩小窗口,直到子数组不再满足>=target

image-20210801164436322

代码如下:

public int minSubArrayLen(int target, int[] nums) {

int result = Integer.MAX_VALUE;

//起、止指针

int start = 0, end = 0;

//总和

int sum = 0;

while (end < nums.length) {

//sum添加,end右移

sum += nums[end++];

while (sum >= target && start < end) {

//因为end++,所以序列长度end - start

result = Math.min(result, end - start);

//移动start

sum -= nums[start++];

}

}

return result == Integer.MAX_VALUE ? 0 : result;

}

⏰ 时间复杂度:O(n),虽然循环里套循环了,但是starrt和end各自被移动了n次,所以时间复杂度是O(n)。

LeetCode219. 存在重复元素 II


☕ 题目:219. 存在重复元素 II (https://leetcode-cn.com/problems/contains-duplicate-ii/)

❓ 难度:简单

📕 描述:

给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。

题目示例

💡思路:

上面我们做了一道滑动窗口的题,我们接着再做一道也可以用滑动窗口解决的问题。

这道题的滑动窗口略有区别,上一道题的窗口是活动的,这个是固定的滑动窗口,维护一个长度为k的固定窗口,如果窗口内含有目标值,返回。如果窗口进入新的元素,就需要把头部的元素移除掉,保持窗口的长度。

固定窗口

代码如下:

public boolean containsNearbyDuplicate(int[] nums, int k) {

HashSet set = new HashSet<>();

for (int i = 0; i < nums.length; i++) {

if (set.contains(nums[i])) {

return true;

}

set.add(nums[i]);

if (set.size() > k) {

set.remove(nums[i - k]);

}

}

return false;

}

⏰ 时间复杂度:O(n)。

LeetCode1052. 爱生气的书店老板


☕ 题目:1052. 爱生气的书店老板(https://leetcode-cn.com/problems/grumpy-bookstore-owner/)

❓ 难度:中等

📕 描述:

今天,书店老板有一家店打算试营业 customers.length 分钟。每分钟都有一些顾客(customers[i])会进入书店,所有这些顾客都会在那一分钟结束后离开。

在某些时候,书店老板会生气。 如果书店老板在第 i 分钟生气,那么 grumpy[i] = 1,否则 grumpy[i] = 0。 当书店老板生气时,那一分钟的顾客就会不满意,不生气则他们是满意的。

书店老板知道一个秘密技巧,能抑制自己的情绪,可以让自己连续 X 分钟不生气,但却只能使用一次。

请你返回这一天营业下来,最多有多少客户能够感到满意。

示例:

输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], X = 3

输出:16

解释:

书店老板在最后 3 分钟保持冷静。

感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16.

💡思路:

这道题是一道固定窗口的问题。

整体思路就是把不生气的部分作为固定窗口,固定窗口把customers分成了三部分,最后求三部分的最大和。

固定窗口

public int maxSatisfied(int[] customers, int[] grumpy, int minutes) {

// 窗口值总和

int winSum = 0;

//左区间总和

int leftSum = 0;

//右区间总和

int rightSum = 0;

int len = customers.length;

//窗口位于起点

for (int i = 0; i < minutes; i++) {

winSum += customers[i];

}

//窗口位于起点时右区间的值

for (int i = minutes; i < len; i++) {

//不生气

if (grumpy[i] == 0) {

rightSum += customers[i];

}

}

//窗口左右-开始移动窗口

int left = 1;

int right = minutes;

int maxSum = winSum + leftSum + rightSum;

//移动

while (right < len) {

//重新计算左区间的值

if (grumpy[left - 1] == 0) {

leftSum += customers[left - 1];

}

//重新计算右区间的值

if (grumpy[right] == 0) {

rightSum -= customers[right];

}

//窗口值

winSum = winSum - customers[left - 1] + customers[right];

//最大总和

maxSum = Math.max(maxSum, leftSum + winSum + rightSum);

//移动固定窗口

left++;

right++;

}

return maxSum;

}

⏰ 时间复杂度:O(n)。

🏠 空间复杂度: O(1)。

原地置换

======================================================================

面试题3. 数组中重复的数字


☕ 题目:面试题3. 数组中重复的数字 (https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/)

❓ 难度:复杂

📕 描述:

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入:

[2, 3, 1, 0, 2, 5, 3]

输出:2 或 3

💡思路:

哈希法

这种找重复的数字问题,我们脑子里第一下就想起来,用Hash存储元素,然后进行比对。

代码实现也很简单:

public int findRepeatNumber(int[] nums) {

HashSet set = new HashSet<>();

for (int i = 0; i < nums.length; i++) {

if (set.contains(nums[i])) {

return nums[i];

}

set.add(nums[i]);

}

return 0;

}

⏰ 时间复杂度:O(n)。

🏠 空间复杂度:O(n)

但今天的主角不是它,而是👇

原地置换法

我们注意到一个条件所有数字都在 0~n-1 的范围内,那就在这方面进行操作,我们可以把元素放到它的值对应的下标的位置。

例如 num[2]=1,那我们就把它放到下标1的位置。

接着遍历,元素发现它应该待的坑已经被它的双胞胎兄弟给占了,它就知道,它是多余的那个。

原地置换

代码如下:

public int findRepeatNumber(int[] nums) {

if (nums.length == 0) {

return -1;

}

for (int i = 0; i < nums.length; i++) {

while (nums[i] != i) {

//判断位置是否被占

int index = nums[i];

if (nums[index] == nums[i]) {

return nums[i];

}

//交换位置

int temp = nums[i];

nums[i] = nums[index];

nums[index] = temp;

}

}

return -1;

}

⏰ 时间复杂度:O(n)。

🏠 空间复杂度:O(1)

LeetCode41. 缺失的第一个正数


☕ 题目:41. 缺失的第一个正数 (https://leetcode-cn.com/problems/first-missing-positive/)

❓ 难度:复杂

📕 描述:

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

题目示例

💡 思路

辅助数组

这道题有一个非常巧妙地的办法![1]

可以引入一个辅助数组,从1开始,在对应的位置存入原数组对应的元素。如原数组num[0]=1,那么这个元素就应该存入辅助数组 helper[1]。

然后遍历辅助数组,发现的第一个坑就是缺失的第一个正数。

辅助数组

代码如下:

public int firstMissingPositive(int[] nums) {

if (nums.length == 0) {

return 1;

}

//辅助数组

int[] helper = new int[nums.length + 1];

//将数组正数元素存入辅助数组中

for (int n : nums) {

if (n > 0 && n < helper.length) {

helper[n] = n;

}

}

//遍历查找,找到不一样元素

for (int i = 1; i < helper.length; i++) {

if (helper[i] != i) {

return i;

}

}

return helper.length;

}

⏰ 时间复杂度:O(n)。

🏠 空间复杂度:O(n)。

原地置换法

我们上面用了原地置换法解决了一个问题,降低了空间复杂度,我们这道题是不是也可以呢?

原地置换没法修改数组长度,我们肯定不能nums[i] 存 i 了,我们左移一下,num[i-1]存i。

原地置换

代码实现如下:

public int firstMissingPositive(int[] nums) {

if (nums.length == 0) {

return 1;

}

//原地置换

for (int i = 0; i < nums.length; i++) {

//将正数填入对应位置

//需要考虑指针移动情况,大于0,小于len+1,不等与i+1,两个交换的数相等时,防止死循环

while (nums[i] > 0 && nums[i] < nums.length + 1 && nums[i] != i + 1 && nums[i] != nums[nums[i] - 1]) {

//下标

int index = nums[i] - 1;

//交换

int temp = nums[index];

nums[index] = nums[i];

nums[i] = temp;

}

}

//遍历置换后的数组

for (int j = 0; j < nums.length; j++) {

if (nums[j] != j + 1) {

return j + 1;

}

}

return nums.length + 1;

}

⏰ 时间复杂度:O(n)。

🏠 空间复杂度:O(1)。

螺旋矩阵

======================================================================

LeetCode54. 螺旋矩阵


☕ 题目:54. 螺旋矩阵 (https://leetcode-cn.com/problems/spiral-matrix/)

❓ 难度:中等

📕 描述:

给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

示例2

💡 思路

这道题,思路比较容易想,就是上右下左四个方向顺时针遍历数组。

顺时针遍历数组

但是这道题的细节是魔鬼。

有两种,一种是一圈遍历完成,上下左右的位置移动,遍历是左闭右开[的条件。

我们采用的是第二种,每遍历完一条边,就移动对应的位置,遍历就是左闭右闭的条件。

还有一点细节就是值得注意的是,遍历过程中可能会出现出现 top > bottom || left > right ,其中一对边界彼此交错了。

这意味着此时所有项都遍历完了,如果没有及时 break ,就会重复遍历。

代码如下:

public List spiralOrder(int[][] matrix) {

List result = new ArrayList<>(16);

//边界

int left = 0, right = matrix[0].length - 1;

int top = 0, bottom = matrix.length - 1;

int size = matrix.length * matrix[0].length;

//遍历

while (result.size() != size) {

//上层遍历

for (int i = left; i <= right; i++) {

result.add(matrix[top][i]);

}

top++;

if (top > bottom) break;

//右层遍历

for (int i = top; i <= bottom; i++) {

result.add(matrix[i][right]);

}

right–;

if (left > right) break;

//下层遍历

for (int i = right; i >= left; i–) {

result.add(matrix[bottom][i]);

}

bottom–;

if (top > bottom) break;

//左层遍历

for (int i = bottom; i >= top; i–) {

result.add(matrix[i][left]);

}

left++;

if (left > right) break;

}

return result;

}

🚗 时间复杂度:O(mn),其中 m 和 n 分别是输入矩阵的行数和列数。

LeetCode59. 螺旋矩阵 II


☕ 题目:59. 螺旋矩阵 II (https://leetcode-cn.com/problems/spiral-matrix-ii/)

❓ 难度:中等

📕 描述:

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例

那么如何才能正确的掌握Redis呢?

为了让大家能够在Redis上能够加深,所以这次给大家准备了一些Redis的学习资料,还有一些大厂的面试题,包括以下这些面试题

  • 并发编程面试题汇总

  • JVM面试题汇总

  • Netty常被问到的那些面试题汇总

  • Tomcat面试题整理汇总

  • Mysql面试题汇总

  • Spring源码深度解析

  • Mybatis常见面试题汇总

  • Nginx那些面试题汇总

  • Zookeeper面试题汇总

  • RabbitMQ常见面试题汇总

JVM常频面试:

Redis高频面试笔记:基础+缓存雪崩+哨兵+集群+Reids场景设计

Mysql面试题汇总(一)

Redis高频面试笔记:基础+缓存雪崩+哨兵+集群+Reids场景设计

Mysql面试题汇总(二)

Redis高频面试笔记:基础+缓存雪崩+哨兵+集群+Reids场景设计

Redis常见面试题汇总(300+题)

Redis高频面试笔记:基础+缓存雪崩+哨兵+集群+Reids场景设计
还有一点细节就是值得注意的是,遍历过程中可能会出现出现 top > bottom || left > right ,其中一对边界彼此交错了。

这意味着此时所有项都遍历完了,如果没有及时 break ,就会重复遍历。

代码如下:

public List spiralOrder(int[][] matrix) {

List result = new ArrayList<>(16);

//边界

int left = 0, right = matrix[0].length - 1;

int top = 0, bottom = matrix.length - 1;

int size = matrix.length * matrix[0].length;

//遍历

while (result.size() != size) {

//上层遍历

for (int i = left; i <= right; i++) {

result.add(matrix[top][i]);

}

top++;

if (top > bottom) break;

//右层遍历

for (int i = top; i <= bottom; i++) {

result.add(matrix[i][right]);

}

right–;

if (left > right) break;

//下层遍历

for (int i = right; i >= left; i–) {

result.add(matrix[bottom][i]);

}

bottom–;

if (top > bottom) break;

//左层遍历

for (int i = bottom; i >= top; i–) {

result.add(matrix[i][left]);

}

left++;

if (left > right) break;

}

return result;

}

🚗 时间复杂度:O(mn),其中 m 和 n 分别是输入矩阵的行数和列数。

LeetCode59. 螺旋矩阵 II


☕ 题目:59. 螺旋矩阵 II (https://leetcode-cn.com/problems/spiral-matrix-ii/)

❓ 难度:中等

📕 描述:

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例

那么如何才能正确的掌握Redis呢?

为了让大家能够在Redis上能够加深,所以这次给大家准备了一些Redis的学习资料,还有一些大厂的面试题,包括以下这些面试题

  • 并发编程面试题汇总

  • JVM面试题汇总

  • Netty常被问到的那些面试题汇总

  • Tomcat面试题整理汇总

  • Mysql面试题汇总

  • Spring源码深度解析

  • Mybatis常见面试题汇总

  • Nginx那些面试题汇总

  • Zookeeper面试题汇总

  • RabbitMQ常见面试题汇总

JVM常频面试:

[外链图片转存中…(img-dx80gIr3-1721146098618)]

Mysql面试题汇总(一)

[外链图片转存中…(img-HCDgVVsS-1721146098619)]

Mysql面试题汇总(二)

[外链图片转存中…(img-hpXcUnva-1721146098619)]

Redis常见面试题汇总(300+题)

[外链图片转存中…(img-0DBgIyxS-1721146098619)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值