相关算法---数组

数组

1. 理论基础

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

数组下标都是从0开始的,内存空间的地址是连续的。因而在删除或者增添元素的时候,难免会移动其他元素的地址。数组的元素是不能删的,只能覆盖。

2. 二分查找

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

题目分析:有序数组;数组中无重复元素。(很适合二分查找

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

3. 移除元素

题目:给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O ( 1 ) O(1) O(1) 额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

题目分析:数组元素只能覆盖。不能进行移除。可以使用快慢指针在一个for循环完成两个for循环的事情。

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

4. 有序数组的平方

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

题目分析:

  • 暴力解决:直接值进行平方,然后再排序。

    class Solution {
        public int[] sortedSquares(int[] nums) {
            int[] arr = new int[nums.length];
            for (int i = 0; i < nums.length; i++) {
                arr[i] = nums[i] * nums[i];
            }
            Arrays.sort(arr);
            return arr;
        }
    }
    
  • 快慢指针:因为数组一开始是有序的,那么平方后最大的值只能是在两端,就可以双指针,一个指向起始位置,一个指向最后位置,向中间不断靠近直到相遇。

    class Solution {
        public int[] sortedSquares(int[] nums) {
            int n = nums.length;
            int[] arr = new int[n];
            int left = 0, right = n - 1;
            int index = n - 1;
            while(left <= right){
                if(nums[left] * nums[left] < nums[right] * nums[right]){
                    arr[index--] = nums[right] * nums[right];
                    right--;
                }else{
                    arr[index--] = nums[left] * nums[left];
                    left++;
                }
            }
            return arr;
        }
    }
    

5. 长度最小的子数组

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

题目分析:用滑动窗口解决问题。滑动窗口就是调节子序列的起始和最终位置来找到结果。滑动窗口的绝妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0; //滑动窗口的起始位置
        int sum = 0; //滑动窗口数值之和
        int result = Integer.MAX_VALUE;
        for(int right = 0; right < nums.length; right++){
            sum += nums[right];
            //每次更新left(起始位置),并不断比较子序列是否符合条件
            while(sum >= target){
                //取得子序列的长度
                result = Math.min(result, right - left + 1);
                //在符合条件下,把窗口缩小看还能不能符合条件,直到找到最小长度
                sum -= nums[left++];
            }
        }
        //如果result没有被赋值的话就表明没有符合条件的子序列,返回0
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

6. 螺旋数组II

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

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

题目分析:循环不变量原则。

模拟顺时针画矩阵的过程:

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

画四条边,每一条边都要坚持一致的左闭右开(或者左开右闭)原则,一圈下来都按照统一的规则画下去,拐角处让新的一条边来继续画。

易错点:
i—>X j—>Y
上下侧是看有好多列 故用j
左右侧是看有好多行 故用i
X Y是i j的起始位置 故下侧和左侧是j > Y i > X

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] res = new int[n][n];

        //循环次数
        int loop = n / 2;

        //定义每次循环起始位置
        int startX = 0, startY = 0;

        //定义偏移量
        int offset = 1;

        //定义填充数字
        int count = 1;

        //定义中间位置
        int mid = n / 2;

        while(loop > 0){
        //i对应X,j对应Y(相当于X横轴,Y纵轴
            int i = startX;
            int j = startY;

            //每一次循环要少前后两个元素 因而offset在后面是+2 X、Y表示i,j下标开始的位置 因为每次只输出一个元素 因而X、Y每次只+1
            
            //模拟上侧从左到右
            for(; j < startY + n - offset; ++j){
                res[startX][j] = count++;
            }

            //模拟右侧从上到下
            for(; i < startX + n - offset; ++i){
                res[i][j] = count++;
            }

            //模拟下侧从右到左
            for(; j > startY; j--){
                res[i][j] = count++;
            }

            //模拟左侧从下到上
            for(; i > startX; i--){
                res[i][j] = count++;
            }

            loop--;

            startX += 1;
            startY += 1;

            offset += 2;
        }

        if(n % 2 == 1){
            res[mid][mid] = count;
        }

        return res;
    }
}

你可能感兴趣的:(算法,算法,leetcode)