Loading

代码随想录(1)-数组

数组是一个非常基础的数据类型。

数组是存放在连续内存空间上的相同类型数据的集合。
下标从零开始,且元素从只能被覆盖不能被删除。

题单

  • 704.二分查找
  • 27.移除元素
  • 977.有序数组的平方
  • 209.长度最小的子数组(middle)
  • 59.螺旋矩阵II

704. 二分查找

题目:给定一个排好序的一维数组和一个查找目标,需要给出目标在数组中的下标,若无则返回-1。

递归-我的解

我通过递归完成了这一题。但观察官方是通过循环完成的。循环的开销小一点,应该更比递归更块一点。

class Solution {
    public int search(int[] nums, int target) {
        return searchWithIndex(nums, target, 0, nums.length - 1);
    }
    public int searchWithIndex(int[] nums, int target, int left, int right){
        if(left > right){
            return -1;
        }
        int middle = (int) (left + right) / 2;
        if( nums[middle] == target ){
            return middle;
        }else if( nums[middle] > target ){
            return searchWithIndex(nums, target, left, middle - 1);
        }else{
            return searchWithIndex(nums, target, left + 1, right);
        }
    }
}

循环

所以我通过循环实现一次。

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while(left <= right ){
            int middle =  (left + right) / 2;
            if( nums[middle] > target ){
                right = middle - 1;
            }else if( nums[middle] < target ){
                left = middle + 1;
            }else{
                return middle;
            }
        }
        return -1;
    }
}

结果对比

结果显示循环确实更快,但是内存并没有更低。我觉得递归方法栈的开销应该比循环体的开销大啊。【挖坑待填】

27. 移除元素

题目:

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

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

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

我的思路:

计数器n为0,遍历数组元素位置i:
  若nums[i]等于val,n++;
  否则,该元素向前移动n个位置。
返回原长度减去n。

代码:

class Solution {
    public int removeElement(int[] nums, int val) {
        int n = 0, len = nums.length ;
        for (int i = 0; i < nums.length; i++) {
            if( nums[i] == val ){
                ++n;
            }else{
                nums[i-n] = nums[i];
            }
        }
        return len - n;
    }
}

2023/01/28 11:47:43
解答成功:
执行耗时:0 ms,击败了100.00% 的Java用户
内存消耗:40 MB,击败了63.71% 的Java用户

977.有序数组的平方

双指针法:核心思路是从两边往中心推进,直至没有元素。

class Solution {
    public int[] sortedSquares(int[] nums) {
        int len = nums.length;
        int[] ans = new int[len];
        int i = 0, j = len - 1;
        while( i <= j ){
            if (nums[i] * nums[i] <= nums[j] * nums[j]) {
                ans[--len] = nums[j] * nums[j];
                j--;
            }else{
                ans[--len] = nums[i] * nums[i];
                i++;
            }
        }
        return ans;
    }
}

209.长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
输入:s = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

额外数组法(我的最早思路)

额外用两个数组分别储存最小的连续个数,这些连续数的和。
然后遍历数组处理,在前一个元素的基础上,更新最小连续个数以及他们的和。

    public int minSubArrayLen(int target, int[] nums) {
        int[] ans = new int[nums.length];  // 当前元素代表和大于等于target的最少的前n个元素(若前面元素相加的最大值,则取最大值)
        int[] sum = new int[nums.length];  // 当前元素代表前n个元素的和
        int min = 1 << 30;
        if(nums == null || nums.length == 0){
            return 0;
        }
        ans[0] = 1;
        sum[0] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            // 首要目标是完成累加
            // 先把当前元素加上前一个元素的结果
            ans[i] = ans[ i - 1 ] + 1;
            sum[i] = sum[ i - 1 ] + nums[i];
            // 若sum大于target,然后对最前的元素进行删减判断,直到前面不能筛
            for (int j = ans[i] - 1; j > 0 && ( sum[i] - nums[i - j] >= target ); j--) {
               sum[i] -= nums[i - j];
               ans[i]--;
            }
            if(sum[i] >= target && ans[i] < min){
               min = ans[i];
            }
        }
        for (int i = 0; i < nums.length; i++) {
            if(sum[i] >= target && ans[i] < min){
                min = ans[i];
            }
        }
        if( min == 1 << 30 ){
            return 0;
        }else {
            return min;
        }

    }

我的代码逻辑有点冗余,阅读题解后,思想可以提炼为滑动窗口的思想。

滑动窗口

使用前后两个下标即可。
遍历右下标,每次加上右下标所在的元素,然后判断左下标是否可以删除,最后判断是否刷新了最短记录。

class Solution {
public int minSubArrayLen(int target, int[] nums) {
        int i = 0, j = 0, sum = 0, min = 1 << 30;
        for (; i < nums.length && j <= i; i++) {
            sum += nums[i];
            while ((sum - nums[j]) >= target) {
                sum -= nums[j];
                j++;
            }
            if (sum >= target && min > (i - j + 1)) {
                min = i - j + 1;
            }

        }
        if( min == 1 << 30 ){
            return 0;
        }else {
            return min;
        }
    }
}

59.螺旋矩阵II

给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]

思路

注意区间,画四条边注意左闭右开。

    public static int[][] generateMatrix(int n) {
        int[][] ans = new int[n][n];
        int loop = (int)( n / 2.0 + 0.5);
        int counter = 1;
        for (int i = 0; i < loop; i++) {
            int x = i, y = i;
            for (; y < n - i - 1 ; y++) {
                ans[x][y] = counter++;
            }
            for (; x < n - i - 1 ; x++) {
                ans[x][y] = counter++;
            }
            for (; y > i ; y--) {
                ans[x][y] = counter++;
            }
            for (; x > i ; x--) {
                ans[x][y] = counter++;
            }
        }
        if( n % 2 == 1){
            ans[loop - 1][loop - 1] = counter;
        }
        return ans;
    }

总结

通过双指针法可以更优雅的完成一些探索区间的任务,减少逻辑判断。
通过螺旋矩阵这一题注意数值区间开闭的重要性。

posted @ 2023-01-28 11:19  丘野  阅读(33)  评论(0编辑  收藏  举报