【LeetCode题解】数组

这篇博客探讨了数组问题的几种常见解题技巧,包括二分查找用于查找元素的边界,双指针解决移除元素和有序数组平方等问题,以及滑动窗口在寻找最小子数组中的应用。通过实例代码详细解析了每种方法的实现过程,有助于提升算法解决实际问题的能力。
摘要由CSDN通过智能技术生成

总结

数组问题可以使用滑动窗口,前缀和,双指针,动态规划, 模拟法技巧

二分查找

34. 在排序数组中查找元素的第一个和最后一个位置

思路

  1. 分别求出左右边界
  2. 再求解

代码

    class Solution {
        public int[] searchRange(int[] nums, int target) {
            if (nums.length == 0) {
                return new int[]{-1,-1};
            }
            int left = searchLeft(nums, target);
            int right = searchRight(nums, target);
            return left == -1 ? new int[]{-1,-1} : new int[]{left,right};
        }
        /**
         * 搜索右边界
         * @param nums
         * @param target
         * @return
         */
        private int searchRight(int[] nums, int target) {
            int left = 0;
            int right = nums.length - 1;
            while (left <= right) {
                int middle = left + (right - left) / 2;
                if (nums[middle] == target) {
                    left = middle + 1;
                } else if (nums[middle] < target) {
                    left = middle + 1;
                } else if (nums[middle] > target) {
                    right = middle - 1;
                }
            }
            if (left - 1 < 0) { // left=right+1, left 的区间是[0,num.length]
                return -1;
            }
            return nums[left - 1] == target ? left - 1 : -1;
        }

        /**
         * 搜索左边界
         * @param nums
         * @param target
         * @return
         */
        private int searchLeft(int[] nums, int target) {
            int left = 0;
            int right = nums.length - 1;
            while (left <= right) { // 
                int middle = left + (right - left) / 2;
                if (nums[middle] == target) {
                    right = middle - 1;
                } else if (nums[middle] < target) {
                    left = middle + 1;
                } else if (nums[middle] > target) {
                    right = middle - 1;
                }
            }
            if (right + 1 >= nums.length) {// right=left-1, left 的区间是[0,num.length], right的区间是[-1,num.length-1],right+1的区间是[0,num.length]
                return -1;
            }
            return nums[right + 1] == target ? right + 1 : -1;
        }
    }

双指针

27. 移除元素

27. 移除元素
诸如「相同元素最多保留 k 位元素」或者「移除特定元素」的问题
总结
对于诸如「相同元素最多保留 k 位元素」或者「移除特定元素」的问题,更好的做法是从题目本身性质出发,利用题目给定的要求提炼出具体的「保留逻辑」,将「保留逻辑」应用到我们的遍历到的每一个位置。
参考资料 【宫水三叶】一题双解 : 「双指针」&「通用」解法

977.有序数组的平方

977.有序数组的平方

滑动窗口

209.长度最小的子数组

209.长度最小的子数组

思路
对于连续子数组/连续子串,一般想到用滑动窗口方法或者动态规划方法进行优化。

代码

    class Solution {
        public int minSubArrayLen(int target, int[] nums) {
            int minLength = Integer.MAX_VALUE;
            int left = 0;
            int right = 0;
            int sum = 0; // 窗口
            while (right < nums.length) {
                sum += nums[right];
                right++;
                while (sum >= target) {
                    minLength = Math.min(minLength, right - left);
                    sum -= nums[left];
                    left++;
                }
            }
            return minLength == Integer.MAX_VALUE ? 0 : minLength;
        }
    }

前缀和

209.长度最小的子数组

螺旋数组

54.螺旋矩阵
剑指Offer 29.顺时针打印矩阵
59.螺旋矩阵II
/**
* 按照右-下-左-上的顺序去生成数组
* 什么时候该改变方向?
* 碰到边界或者碰到已经生成的元素。
* 怎么控制方向?
* 定义一个方向数组与方向遍历direction direction%4表示当前方向,每次改变方向后,direction++
* 什么时候跳出循环?
* 当四个方向都行不通的时候

        int[][] result = new int[n][n];
        int[] dx = new int[]{0,1,0,-1};
        int[] dy = new int[]{1,0,-1,0};
        int direction = 0;
        int val = 1;
        int x = 0;
        int y = 0;
        while(val <= n*n){
            result[x][y]=val;
            int newX = x+dx[direction%4];
            int newY = y+dy[direction%4];
            if(newX<0||newX>=n||newY<0||newY>=n||result[newX][newY]!=0){
                direction++;
                newX = x+dx[direction%4];
                newY = y+dy[direction%4];
            }
            x=newX;
            y=newY;
            val++;
        }
        return result;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值