代码随想录-数组理论基础

数组理论基础

二分查找

代码随想录 (programmercarl.com)

二分查找前提条件:有序数组且无重复元素,想好是用左闭右闭还是左闭右开!

  • 如果是前者,while(left <= right),left==right是有意义的,后续if(nums[middle] > target),right要赋值为middle-1,因为当前的middle已经判断不等于,所以接下来查找的区间为middle-1
  • 如果是后者,while(left < right), left==right无意义,后续的比较right就可以更新为middle,即:下一个查询区间不会去比较nums[middle]
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9     
输出: 4       
解释: 9 出现在 nums 中并且下标为 4     
// 采用left <= right
public int search(int[] nums, int target){
        // 比较首尾提前判断
        if (target < nums[0] || target > nums[nums.length - 1]) {
            return -1;
        }
        int left = 0, right = nums.length-1;
        // left < right
        while (left <= right) {
            // 位运算,相当于/2
            int mid = left + ((right - left) >> 1);
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                // left = mid;
                left = mid + 1;
            } else if (nums[mid] > target) {
                // right = mid;
                right = mid - 1;
            }
        }
        return -1;
    }

移除元素(暴力&双指针)

代码随想录 (programmercarl.com)

要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖(从后往前移)。

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

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

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

示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
// 暴力
public static int solution(int[] nums, int val) {
        // 定义数组长度,用于后续删减
        int size = nums.length;
        for (int i = 0; i < size; i++) {
            // 如果是目标数则将后续元素向前移,同时减掉i和size的数值
            if (nums[i] == val) {
                for (int j = i + 1; j < size; j++) {
                    nums[j - 1] = nums[j];
                }
                i--;
                size--;
            }
        }
        return size;
    }

// 快慢指针
public static int removeElement(int[] nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
            // 如果是目标数的话,只增加fast,反之两者都加,最后取slow
            if (nums[fastIndex] != val) {
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }
        }
        return slowIndex;
    }

有序数组的平方(暴力&双指针)

代码随想录 (programmercarl.com)

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

示例 1: 输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]
// 暴力,不需要管数字是否按顺序
public void sortedArr() {
        int[] arr = {-4, -1, 0, 3, 10};
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr[i] * arr[i];
        }
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
    }

// 双指针,前提是数组是排好序的
public void squreArrSorted(int[] arr){
    	// 设置双指针
        int right = arr.length - 1;
        int left = 0;
    	// 新数组用来存放数据
        int[] result = new int[arr.length];
        int index = arr.length - 1;
    	// 因为排完序后,数的平方(最大值)一定是在两边的,所以index从后往前
        while (left <= right) {
            if (arr[left] * arr[left] > arr[right] * arr[right]) {
                result[index--] = arr[left] * arr[left];
                ++left;
            } else {
                result[index--] = arr[right] * arr[right];
                --right;
            }
            System.out.println(Arrays.toString(result));
        }
    }

长度最小的子数组(滑动窗口)

代码随想录 (programmercarl.com)

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

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

滑动窗口:不断调节子序列的起始位置和终止位置,从而得出我们想要的结果

  • 窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组
  • 窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)
  • 窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引
public static void main(String[] args) {
        int[] nums = {2, 3, 1, 2, 4, 3};
        int target = 7;
        int left = 0, sum = 0;
        // 假定一个最小值,如果最小值没有出现,在后续三元运算中处理
        int result = Integer.MAX_VALUE;
        // 开始滑动
        for (int right = 0; right < nums.length; right++) {
            sum += nums[right];
            // 如果总数等于目标值,进行判断,大于的情况就移动左指针同时减少总数
            while (sum >= target) {
                // 获取子数组最小值
                result = Math.min(result, right - left + 1);
                sum -= nums[left++];
            }
        }
        // 用三元运算符处理最小值,如果没有的话就返回0
        result = result == Integer.MAX_VALUE ? 0 : result;
        System.out.println(result);
    }

螺旋矩阵

代码随想录 (programmercarl.com)

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

示例:

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

坚持循环不变量原则,模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去

public int[][] generateMatrix(int n) {
        // n:表示n*n的数组
        int[][] res = new int[n][n];
        // 每次循环开始点,圈数,起始数(填充数字)
        int start = 0, loop = 0, count = 1;
        int i, j = 0;
        // 如果n/2(表示一共需要转几次圈)为奇数,中心点需要手动赋值
        while (loop++ < n / 2) {
            // 上侧从左往右,都是左闭右开(如果n=3,则填充0和1,2留到下一个循环使用)
            for (j = start; j < n - loop; j++) {
                res[start][j] = count++;
            }
            // 右侧从上往下
            for (i = start; i < n - loop; i++) {
                res[i][j] = count++;
            }
            // 下测从右往左
            for (; j >= loop; j--) {
                res[i][j] = count++;
            }
            // 左侧从下往上
            for (; i >= loop; i--) {
                res[i][j] = count++;
            }
            // 每转完一圈需要在起始点加一
            start++;
        }
        
        // 如果转的圈数为奇数,中心点需要手动赋值
        if (n % 2 == 1) {
            res[start][start] = count;
        }
        return res;
    }
posted @ 2023-02-19 17:01  颜骏  阅读(36)  评论(0编辑  收藏  举报