• 【小航的算法日记】数组


    一、概念

    数组是存放在连续内存空间上的相同类型数据的集合。

    二、模板

    二分

    三、例题

    题:704. 二分查找

    给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

    示例 1:

    输入: nums = [-1,0,3,5,9,12], target = 9
    输出: 4
    解释: 9 出现在 nums 中并且下标为 4
    
    • 1
    • 2
    • 3

    示例 2:

    输入: nums = [-1,0,3,5,9,12], target = 2
    输出: -1
    解释: 2 不存在 nums 中因此返回 -1
    
    • 1
    • 2
    • 3

    提示:

    你可以假设 nums 中的所有元素是不重复的。
    n 将在 [1, 10000]之间。
    nums 的每个元素都将在 [-9999, 9999]之间。
    
    • 1
    • 2
    • 3

    解:

    解题思路:二分

    AC代码:

    class Solution {
        public int search(int[] nums, int target) {
            // (]
            int l = 0;
            int r = nums.length;
            while(l < r) {
                int mid = l + ((r - l) >> 1);
                if(nums[mid] > target) {
                    r = mid;
                } else if(nums[mid] < target) {
                    l = mid + 1;
                } else {
                    return mid;
                }
            }
            return -1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    解题思路:二分

    AC代码:

    class Solution {
        public int search(int[] nums, int target) {
            // []
            int l = 0; int r = nums.length - 1;
            while(l <= r) {
                int mid = l + ((r - l) >> 1);
                if(nums[mid] < target) {
                    l = mid + 1;
                } else if(nums[mid] > target) {
                    r = mid - 1;
                } else {
                    return mid;
                }
            } 
            return -1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    题:27. 移除元素

    给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

    不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

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

    说明:

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

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

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

    // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
    int len = removeElement(nums, val);
    
    // 在函数里修改输入数组对于调用者是可见的。
    // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
    for (int i = 0; i < len; i++) {
        print(nums[i]);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    示例 1:

    输入:nums = [3,2,2,3], val = 3
    输出:2, nums = [2,2]
    解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
    
    • 1
    • 2
    • 3

    示例 2:

    输入:nums = [0,1,2,2,3,0,4,2], val = 2
    输出:5, nums = [0,1,4,0,3]
    解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
    
    • 1
    • 2
    • 3

    提示:

    0 <= nums.length <= 100
    0 <= nums[i] <= 50
    0 <= val <= 100
    
    • 1
    • 2
    • 3

    解:

    解题思路:快慢指针

    AC代码:

    class Solution {
        public int removeElement(int[] nums, int val) {
            int p = 0; int q = 0;
            int len = nums.length;
            for(; p < len; ++ p) {
                if(nums[p] != val) {
                    nums[q ++] = nums[p];
                }
            }
            return q;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    解题思路:相向双指针法

    AC代码:

    class Solution {
        // 相向双指针法
        public int removeElement(int[] nums, int val) {
            int len = nums.length;
            int l = 0; int r = len - 1;
            while(l <= r) {
                while(l <= r && nums[l] != val) ++ l;
                while(l <= r && nums[r] == val) -- r;
                if(l < r) {
                    nums[l ++] = nums[r --];
                }
            }
            return l;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    题:977. 有序数组的平方

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

    示例 1:

    输入:nums = [-4,-1,0,3,10]
    输出:[0,1,9,16,100]
    解释:平方后,数组变为 [16,1,0,9,100]
    排序后,数组变为 [0,1,9,16,100]
    
    • 1
    • 2
    • 3
    • 4

    示例 2:

    输入:nums = [-7,-3,2,3,11]
    输出:[4,9,9,49,121]
    
    • 1
    • 2

    提示:

    1 <= nums.length <= 104
    -104 <= nums[i] <= 104
    nums 已按 非递减顺序 排序
    
    • 1
    • 2
    • 3

    进阶:

    请你设计时间复杂度为 O(n) 的算法解决本问题
    
    • 1

    解:

    解题思路:双指针法

    在这里插入图片描述

    AC代码:

    class Solution {
        // 双指针法
        public int[] sortedSquares(int[] nums) {
            int len = nums.length;
            int k = len - 1;
            int[] res = new int[len];
            for(int i = 0, j = len - 1; i <= j;) {
                if(nums[i] * nums[i] > nums[j] * nums[j]) {
                    res[k --] = nums[i] * nums[i];
                    i ++;
                } else {
                    res[k --] = nums[j] * nums[j];
                    j --;
                }
            }
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    题:209. 长度最小的子数组

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

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

    示例 1:

    输入:target = 7, nums = [2,3,1,2,4,3]
    输出:2
    解释:子数组 [4,3] 是该条件下的长度最小的子数组。
    
    • 1
    • 2
    • 3

    示例 2:

    输入:target = 4, nums = [1,4,4]
    输出:1
    
    • 1
    • 2

    示例 3:

    输入:target = 11, nums = [1,1,1,1,1,1,1,1]
    输出:0
    
    • 1
    • 2

    提示:

    1 <= target <= 109
    1 <= nums.length <= 105
    1 <= nums[i] <= 105
    
    • 1
    • 2
    • 3

    进阶:

    如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。
    
    • 1

    解:

    解题思路:滑动窗口

    AC代码:

    class Solution {
        // 滑动窗口
        public int minSubArrayLen(int target, int[] nums) {
            int res = Integer.MAX_VALUE; 
            for(int l = 0, r = 0, len = 0, sum = 0; r < nums.length; ++ r) {
                // 加入窗口
                sum += nums[r];
                // 尝试缩减窗口,取最小
                while(sum >= target) {
                    len = r - l + 1; // 更新窗口长度
                    res = res > len ? len : res;
                    sum -= nums[l ++]; // 缩减窗口
                }
            }
            return res == Integer.MAX_VALUE ? 0 : res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    解题思路:前缀和 + 二分

    预处理 => 前缀和数组 => 本身具有单调递增 => 二分

    AC代码:

    class Solution {
        public int minSubArrayLen(int target, int[] nums) {
            int n = nums.length, ans = n + 10;
            int[] sum = new int[n + 10]; // 前缀和
            for(int i = 1; i <= n; ++ i) {
                sum[i] = sum[i - 1] + nums[i - 1];
            }
            // 遍历前缀和,具有单增行,开始二分查找
            for(int i = 1; i <= n; ++ i) {
                int s = sum[i], d = s - target;
                // (,] r是我们需要的结果
                int l = 0, r = i;
                while(l < r) {  
                    int mid = l + r + 1 >> 1; // 向上取整
                    if(sum[mid] <= d) l = mid;
                    else r = mid - 1;
                }
                if(sum[r] <= d) ans = Math.min(ans, i - r);
            }
            return ans == n + 10 ? 0 : ans;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    题:59. 螺旋矩阵 II

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

    示例 1:
    在这里插入图片描述

    输入:n = 3
    输出:[[1,2,3],[8,9,4],[7,6,5]]
    
    • 1
    • 2

    示例 2:

    输入:n = 1
    输出:[[1]]
    
    • 1
    • 2

    提示:

    1 <= n <= 20
    
    • 1

    解:

    解题思路:模拟

    AC代码:

    class Solution {
        public int[][] generateMatrix(int n) {
            int[][] res = new int[n][n];
            int startx = 0, starty = 0; // 每圈的起始点
            int loop = n / 2; // 转的圈数
            int offset = 1; // 每一条边遍历的长度
            int i, j;
            int cnt = 1; // 计数
            while((loop --) > 0) {
                i = startx; j = starty;
                // 保持左开右闭原则
                // 1.左到右
                for(j = starty; j < n - offset; ++ j) res[i][j] = cnt ++;
                // 2.上到下
                for(i = startx; i < n - offset; ++ i) res[i][j] = cnt ++;
                // 3.右到左
                for(; j > starty; -- j) res[i][j] = cnt ++;
                // 4.下到上
                for(; i > startx; -- i) res[i][j] = cnt ++;
                startx ++; starty ++;
                offset ++; // 圈数+1
            }
            if((n & 1) != 0) res[n / 2][n / 2] = cnt;
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  • 相关阅读:
    基金客户和销售机构
    【MongoDB】docker部署社区版(一)
    制造企业如何打造客户服务核心竞争力?[AMT企源典型案例]
    有了HTTP,为什么还要RPC?
    MASM32v11编程调用Process32First失败: 程序发出命令,但命令长度不正确
    理解3ds max 中的衰减贴图
    深入剖析Golang中单例模式
    springBoot与Vue共同搭建webSocket环境
    CSP-J第二轮试题-2022年-3题
    Xposed项目配置
  • 原文地址:https://blog.csdn.net/m0_51517236/article/details/125419820