Array

117 阅读4分钟

1. 数组基础理论

数组是存放在连续内存空间上的相同类型数据的集合。数组可以方便的通过下标索引的方式获取到下标下对应的数据。

需要两点注意的是:

  • 数组下标都是从0开始的。
  • 数组内存空间的地址是连续的

因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。数组的元素是不能删的,只能覆盖。

2. 二分查找 704. Binary Search 💚

前提:

  • 有序数组
  • 数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的

思路:重中之重是确定好边界条件,这里使用左闭右闭[left, right] while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <= if (nums[middle] < target) left 要赋值为 middle + 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle +1。

class Solution{
    public int search(int[] nums, int target) {
        int low = 0;
        int high = nums.length -1;
        while(low <= high){
           int  mid = low + (high - low)/2;
            if(nums[mid] == target){
                return mid;
            }
            if(nums[mid] < target){
                low = mid + 1;
            }else{
                high = mid - 1;
            }
        }
        return -1;
    }
}
//time:O(log n)

3. 移除元素 27. Remove Element 💚

双指针: 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。 定义快慢指针 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组 慢指针:指向更新 新数组下标的位置 time: O(n)因为只有一个for loop 思路:快指针遍历,把值不等于要删除的数,赋给慢指针。当快指针的值等于要删除的元素时,快指针继续往后走,慢指针不动。

class Solution {
    public int removeElement(int[] nums, int val) {
        // 快慢指针
        // time :O(n)
        int slow = 0;
        int fast = 0;
        while(fast < nums.length){
            if(nums[fast] != val){
                nums[slow] = nums[fast];
                slow++;
            }
            fast++;
        }
        return slow;
    }
}

4. 有序数组的平方 977. Squares of a Sorted Array 💚

思路:双指针 数组其实是有序的, 只不过负数平方之后可能成为最大数了。那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。此时可以考虑双指针法了,i指向起始位置,j指向终止位置。

定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。

  • 如果A[i] * A[i] < A[j] * A[j] 那么result[k--] = A[j] * A[j]; 。
  • 如果A[i] * A[i] >= A[j] * A[j] 那么result[k--] = A[i] * A[i];
class Solution {
    public int[] sortedSquares(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        int[] res = new int[nums.length];
        for(int k = nums.length - 1; k >= 0; k--){
            if(nums[left] * nums[left] >= nums[right] * nums[right]){
                res[k] = nums[left] * nums[left];
                left++;
            }else{
                res[k] = nums[right] * nums[right];
                right--;
            }
        }
        return res;
    }
}
//time: O(n)

5. 长度最小的子数组 209. Minimum Size Subarray Sum 🧡

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

在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。

那么滑动窗口如何用一个for循环来完成这个操作呢。

首先要思考 如果用一个for循环,那么应该表示 滑动窗口的起始位置,还是终止位置。如果只用一个for循环来表示 滑动窗口的起始位置,那么如何遍历剩下的终止位置?此时难免再次陷入 暴力解法的怪圈。

所以 只用一个for循环,那么这个循环的索引,一定是表示 滑动窗口的终止位置。

那么问题来了, 滑动窗口的起始位置如何移动呢? 在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置? 窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。

窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。

窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

简单来说,就是移动终止位置,直到窗口中的数大于等于目标值,然后移动开始位置,找到最小数组。然后继续移动终止位置...循环 时间复杂度: O(n)。不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。

注意最终return时的res判断,有可能没有找到,所以要判断一下,return 0

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int start = 0;
        int res = Integer.MAX_VALUE;
        int sum = 0;
        for (int end = 0; end < nums.length; end++){
            sum += nums[end];
            while(sum >= target){
                int step = end - start + 1;
                res = res < step ? res : step;
                sum = sum - nums[start];
                start++;
            }
        }
        return res == Integer.MAX_VALUE ? 0 : res;
    }
}
//time: O(n)
//space:O(1)

6. 螺旋矩阵

6.1 螺旋矩阵 54. Spiral Matrix 🧡

思路: 循环不变量,循环时,每条边的处理规则应该相同

对于每一条边,边界条件都是处理所有数,对于处理完成的边,移动整条边界。

如首先处理最上面的边,处理完成后,把整条上边界下移,即++up。 并判断up下移后是否在down的下面,如果在,则说明已经螺旋完成,break退出循环。up加完过后,右边处理时,up的此时值为1,即跳过已经处理好的右上角。

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        int m = matrix.length;//宽
        int n = matrix[0].length;//长
        int left = 0;
        int right = n - 1;
        int up = 0;
        int down = m - 1;
        List<Integer> res = new ArrayList<>();
        while(true){
            for(int i = left; i <= right; i++){
                res.add(matrix[up][i]);
            }
            if(++up > down){
                break;
            }
            
            for(int i = up; i <= down; i++){
                res.add(matrix[i][right]);
            }
            if(--right < left){
                break;
            }
            
            for(int i = right; i >= left; i--){
                res.add(matrix[down][i]);
            }
            if(--down < up){
                break;
            }
            
            for(int i = down; i >= up; i--){
                res.add(matrix[i][left]);
            }
            if(++left > right){
                break;
            }
        }
        return res;
    }
}
//time O(m*n)
//space O(1)

6.2 螺旋矩阵II 59. Spiral Matrix II 🧡

class Solution {
    public int[][] generateMatrix(int n) {
        //循环不变量
        //循环时,每条边的处理规则应该相同
        //左闭右开,处理第一个节点,最后一个节点留给下一条边处理
        int left = 0;
        int right = n - 1;
        int up = 0;
        int down = n - 1;
        int count = 1;
        int[][] res = new int[n][n];
        while(true){
            for(int i = left; i <= right; i++){
                res[up][i] = count;
                count++;
            }
            if(++up > down){
                break;
            }
            
            for(int i = up; i <= down; i++){
                res[i][right] = count;
                count++;
            }
            if(--right < left){
                break;
            }
        
            for(int i = right; i >= left; i--){
                res[down][i] = count;
                count++;
            }
            if(--down < up){
                break;
            }
            
            for(int i = down; i >= up; i--){
                res[i][left] = count;
                count++;
            }
            if(++left > right){
                break;
            }
        }
        return res;
    }
}