1.移除元素(27-易)
题目描述:不使用额外空间(原地),移除数组nums中所有值等于val的元素,返回移除后的数组长度。你不需要考虑数组中超出新长度后面的元素!
示例:
给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 注意这五个元素可为任意顺序。 --------------------------------------------------------------------- 为什么返回数值是整数,但输出的答案是数组呢? 请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 你可以想象内部操作如下: // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝 int len = removeElement(nums, val); // 在函数里修改输入数组对于调用者是可见的。 // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 for (int i = 0; i < len; i++) { print(nums[i]); }
思路:由于数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖!所以分两步走,先找到该值,然后更新数组。根据时间复杂度和更新方式不同,可以分为暴力求解和双指针方法。
法1.暴力求解:每次找到要删除的元素,将剩余数组整体前移一个位置,更新索引,注意要动态的更新索引与数组长度。
法2.双指针:定义两个指针,fast
指针遍历数组寻找不为val的值赋给slow
指针,同时更新slow
指针。这样快指针遍历数组,通过慢指针实现删除(覆盖)。
代码1:(暴力求解)
public int removeElement(int[] nums, int val) { int n = nums.length; for (int i = 0; i < n; i++) { if (nums[i] == val) { for (int j = i + 1; j < n; j++) { nums[j - 1] = nums[j]; //前移覆盖 } i--; //整体前移,所以i也要前移一位 n--; //改变数组-1 } } return n; }
代码2:(双指针)
public int removeElement(int[] nums, int val) { int slow = 0; for (int fast = 0; fast < nums.length; fast++) { if (nums[fast] != val) { nums[slow++] = nums[fast]; } } return slow; }
2.移动零(283-易)
题目描述:在保证非0元素相对顺序前提下,将0元素移到数组末尾,原地移动。
示例:
输入: [0,1,0,3,12] 输出: [1,3,12,0,0]
思路:参照27移除元素,即使用双指针:快指针寻找不等于0数值与慢指针进行交换,注意与27题覆盖不同,当快指针指向值不等于0时慢指针也移动(即相当于自己和自己交换)。
代码:
public void moveZeroes(int[] nums) { int slow = 0; int tmp; for (int fast = 0; fast < nums.length; fast++) { if (nums[fast] != 0) { tmp = nums[slow]; nums[slow++] = nums[fast]; nums[fast] = tmp; } } }
3.螺旋矩阵II(59-中)
题目描述:生成1-n^2的所有元素,且元素按顺时针螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
思路:模拟顺时针螺旋填充必须按照统一的规则(四个方向,每圈每个方向填入固定数量的值)进行填充。这里使用左闭右开循环填充。
代码:
public int[][] generateMatrix(int n) { int[][] matrix = new int[n][n]; int x = 0, y = 0; //1.每一圈的起始位置 int loop = n / 2; //2.循环的圈数 int offset = 1; //3.控制每一条边遍历的长度!! int count = 1; //4.赋值(未填充位置) int mid = loop; //5.中间位置(奇数情况填充) int i, j; //6.坐标 while (loop-- > 0) { i = x; j = y; //模拟从左向右 for (j = y; j < y + n - offset; j++) { matrix[x][j] = count++; } //模拟从上到下 for (i = x; i < x + n - offset; i++) { matrix[i][j] = count++; } //模拟从右向左 for (; j > y; j--) { matrix[i][j] = count++; } //模拟从下到上 for (; i > x; i--) { matrix[i][j] = count++; } //下一圈,改变起始位置坐标 x++; y++; offset += 2; //偏移量(注:起始位置改变) } //奇数情况 if (n % 2 != 0) { matrix[mid][mid] = count++; } return matrix; }
4.数组中最长连续的1(485-易)
题目描述:二进制数组中,找到最大连续1的个数。
示例:
输入: [1,1,0,1,1,1] 输出: 3 解释: 开头的两位和最后的三位都是连续1,所以最大连续1的个数是 3.
思路:
法1.暴力遍历,当前值如果等于0,当前最大值为0,不为0则递增+1。并更新系统最大值。
法2.双指针:关键找到最开始出现1的位置,固定左指针,右指针继续寻找,当不满足右指针不等于1时,更新此时最长子数组。
代码1:暴力遍历
public int findMaxConsecutiveOnes(int[] nums) { int res = 0, cur = 0; for (int x : nums) { cur = x == 0 ? 0 : cur + 1; res = Math.max(res, cur); } return res; }
代码2:双指针
public int findMaxConsecutiveOnes(int[] nums) { int i = 0, j = 0; int res = 0; while (j < nums.length) { if (nums[j] == 1) { i = j; //首次出现1,固定左指针 while(j < nums.length && nums[j] == 1) j++; res = Math.max(res, j - i); } else { j++; //不满足,直接跳过 } } return res; }
5.搜索二维矩阵II(240-中)
题目描述:在有序矩阵中寻找指定数值。
- 每行的元素从左到右升序排列。
- 每列的元素从上到下升序排列。
示例:
输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5 输出:true
思路:本题关键解题关键是矩阵有序,我们可以从右上角或者左下角出发,遍历寻找目标值。
以右上角为例,当前遍历左边的元素比当前值小,当前遍历下边的元素比当前值大。
代码:时间复杂度:O(m + n)
public boolean searchMatrix(int[][] matrix, int target) { int i = 0, j = matrix[0].length - 1; while (i < matrix.length && j > -1) { if (matrix[i][j] == target) return true; else if (matrix[i][j] > target) { j--; } else { i++; } } return false; }