Leetcode --- 数组与矩阵(补充1)

简介: Leetcode --- 数组与矩阵(补充1)

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;
}


相关文章
|
2月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
39 0
|
4月前
|
存储 算法 NoSQL
LeetCode第73题矩阵置零
文章介绍了LeetCode第73题"矩阵置零"的解法,通过使用矩阵的第一行和第一列作为标记来记录哪些行或列需要置零,从而在不增加额外空间的情况下解决问题。
LeetCode第73题矩阵置零
|
4月前
|
算法
LeetCode第53题最大子数组和
LeetCode第53题"最大子数组和"的解题方法,利用动态规划思想,通过一次遍历数组,维护到当前元素为止的最大子数组和,有效避免了复杂度更高的暴力解法。
LeetCode第53题最大子数组和
|
2月前
【LeetCode-每日一题】 删除排序数组中的重复项
【LeetCode-每日一题】 删除排序数组中的重复项
21 4
|
2月前
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
19 0
Leetcode第三十三题(搜索旋转排序数组)
|
2月前
|
算法 C++
Leetcode第59题(螺旋矩阵2)
这篇文章介绍了解决LeetCode第59题“螺旋矩阵II”的算法,通过C++编程实现按顺时针顺序填充一个n x n的正方形矩阵。
17 0
|
2月前
|
算法 C++
Leetcode第53题(最大子数组和)
这篇文章介绍了LeetCode第53题“最大子数组和”的动态规划解法,提供了详细的状态转移方程和C++代码实现,并讨论了其他算法如贪心、分治、改进动态规划和分块累计法。
68 0
|
2月前
|
C++
【LeetCode 12】349.两个数组的交集
【LeetCode 12】349.两个数组的交集
17 0
|
4月前
|
算法
LeetCode第81题搜索旋转排序数组 II
文章讲解了LeetCode第81题"搜索旋转排序数组 II"的解法,通过二分查找算法并加入去重逻辑来解决在旋转且含有重复元素的数组中搜索特定值的问题。
LeetCode第81题搜索旋转排序数组 II
|
4月前
|
算法 索引
LeetCode第34题在排序数组中查找元素的第一个和最后一个位置
这篇文章介绍了LeetCode第34题"在排序数组中查找元素的第一个和最后一个位置"的解题方法,通过使用双指针法从数组两端向中间同时查找目标值,有效地找到了目标值的首次和最后一次出现的索引位置。
LeetCode第34题在排序数组中查找元素的第一个和最后一个位置