01-数组类

数组理论基础

数组是存放在连续内存相同类型数据的集合 通过下标索引的方式获取对应下标下对应的数据 数组下标从0开始
因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址
数组增加或删除操作复杂 数组的元素不能删,只能覆盖
数组查询操作简单
Java二维数组的地址值并不是连续的
排列方式如下:
在这里插入图片描述

二分查找

特征

升序、无重复的数组查询

易错点

1. while(left<=right) or while(left<right)
2. if(arr[mid]>target) right = mid-1; or  if(arr[mid]>target) right = mid;
3. righr = arr.length-1;  or   righr = arr.length;

两种写法

  1. [left,right] [1,1] 左闭右闭
  2. [left,right) [1,2) 左闭右开

题目[二分查找]

704 二分查找

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

在这里插入图片描述

/*
解法1:【left,right】
*/
class Solution {
    public int search(int[] nums, int target) {
        if(nums.length==0){
            return -1;
        }
        int left = 0;
        // 注意点
        int right = nums.length-1;
        // 注意点
        while(left <= right){
            int mid = (left + right)/2;
            // 注意点
            if(nums[mid] > target){
                right = mid -1;
            }
            if(nums[mid] < target){
                left = mid + 1;
            }
            if(nums[mid] == target){
                return mid;
            }            
        }
        return -1;
    }
}
/*
解法2:【left,right)
*/
class Solution {
    public int search(int[] nums, int target) {
        if(nums.length==0){
            return -1;
        }
        int left = 0;
        // 注意点
        int right = nums.length;
        // 注意点
        while(left < right){
            int mid = (left + right)/2;
            // 注意点
            if(nums[mid] > target){
                right = mid ;
            }
            if(nums[mid] < target){
                left = mid + 1;
            }
            if(nums[mid] == target){
                return mid;
            }            
        }
        return -1;
    }
}

35 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。假设数组无重复元素
在这里插入图片描述
思路:

  1. 目标值在数组所有元素之前
  2. 目标值等于数组的某个元素
  3. 目标值插入数组的位置
  4. 目标值在数组所有元素之后
/*

解法1: 左比右闭
*/
class Solution {
    public int searchInsert(int[] nums, int target) {
        if(nums.length == 0){
            return 0;
        }
        int left = 0;
        int right = nums.length -1;  
        // target在数组元素中
        while(left <= right){
            int mid = (left + right)/2;
            if(nums[mid] > target){
                right = mid - 1;
            }else if(nums[mid] < target){
                left = mid + 1;
            }else{
                return mid;
            }
        }
        // target不在数组元素中,在数组元素之前
        // target在数组元素之后
        // target插入数组的位置
        return right + 1;
        
    }
}
/*

解法2: 左比右开
*/
class Solution {
    public int searchInsert(int[] nums, int target) {
        if(nums.length == 0){
            return 0;
        }
        int left = 0;
        int right = nums.length;  
        // target在数组元素中
        while(left < right){
            int mid = (left + right)/2;
            if(nums[mid] > target){
                right = mid ;
            }else if(nums[mid] < target){
                left = mid + 1;
            }else{
                return mid;
            }
        }
        // target不在数组元素中,在数组元素之前
        // target在数组元素之后
        // target插入数组的位置
        return right;
        
    }
}

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

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。
在这里插入图片描述
思路:

  1. target 在数组范围的右边或者左边,返回{-1, -1}
  2. target 在数组范围中,且数组中不存在target,返回{-1, -1}
  3. target 在数组范围中,且数组中存在target,返回{开始位置, 结束位置}

找左边界与右边界,然后判断三种类型

class Solution {
    int[] searchRange(int[] nums, int target) {
        int leftBorder = getLeftBorder(nums, target);
        int rightBorder = getRightBorder(nums, target);
        // 情况一
        if (leftBorder == -2 || rightBorder == -2) return new int[]{-1, -1};
        // 情况三
        if (rightBorder - leftBorder > 1) return new int[]{leftBorder + 1, rightBorder - 1};
        // 情况二
        return new int[]{-1, -1};
    }

    int getRightBorder(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target) {
                right = middle - 1;
            } else { // 寻找右边界,nums[middle] == target的时候更新left
                left = middle + 1;
                rightBorder = left;
            }
        }
        return rightBorder;
    }

    int getLeftBorder(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
                right = middle - 1;
                leftBorder = right;
            } else {
                left = middle + 1;
            }
        }
        return leftBorder;
    }
}

69. x的算数平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
在这里插入图片描述
思路:0为左,x为右,就是求k的平方小于等于x时,k的最大值

class Solution {
    public int mySqrt(int x) {
        int l =0;
        int r = x;
        int ans = -1;
        while(l<=r){
            int mid = l + (r-l)/2;
            // 解决范围不够用
            if((long)mid*mid<=x){
                ans = mid;
                l = mid + 1;
            }else{
                r = mid -1;
            }            
        }    
        return ans;
    }
}

367. 有效的完全平方数

给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
进阶:不要 使用任何内置的库函数,如 sqrt 。

在这里插入图片描述
思路: 左为0,右为num 然后用二分查询 就好了

class Solution {
    public boolean isPerfectSquare(int num) {
        int left = 0,right = num;
        while(left <= right){
            int mid = (left + right)/2;
            if((long)mid*mid > num){
                right = mid -1;
            }else if((long)mid * mid < num){
                left = mid +1;
            }else{
               return true; 
            }
        }
        return false;
    }
}

题目[移除元素]

要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖

27 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度
在这里插入图片描述
思路: slowIndex 用于标记覆盖的位置 fastIndex用于标记不等于val的元素 然后进行相应的覆盖 就可以了,并对slowIndex fastIndex自增

 public int removeElement(int[] nums, int val) {
       
        // 双指针(快慢指针法)
        if(nums.length == 0){
            return 0;
        }
        // 标记要覆盖的位置
        int slowIndex=0;
        // 标记不等于val的位置
        int quickIndex ;
        for(quickIndex = 0;quickIndex<nums.length;quickIndex++){
            if(nums[quickIndex]!=val){
                nums[slowIndex] = nums[quickIndex];
                slowIndex++;
            }

        }
        return slowIndex;

26. 删除有序数组中的重复项

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持一致
在这里插入图片描述

class Solution {
    public int removeDuplicates(int[] nums) {
        /*

            双指针---快慢指针

        */
        if(nums.length==0){
            return 0;
        }

        int slowIndex = 0;
        int fastIndex = 0;

        for(fastIndex = 0;fastIndex < nums.length;fastIndex++){
            if(nums[slowIndex] != nums[fastIndex]){
                nums[++slowIndex] = nums[fastIndex];
            }
        }
        return slowIndex+1;
    }
}

283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作
思路:将不是0的位置上往前移,然后将对应数量的0补充在数组后面

class Solution {
    public void moveZeroes(int[] nums) {
    /*
	 双指针(快慢)

	*/
        if(nums.length==0)
            return;    
        int slowIndex = 0,fastIndex = 0;
        for(;fastIndex<nums.length;fastIndex++){
            if(nums[fastIndex] != 0){
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }

        }
        for(int i=0;i<nums.length-slowIndex;i++){
            nums[slowIndex + i] = 0;
        }

    }
}

844. 比较含退格的字符串

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。注意:如果对空文本输入退格字符,文本继续为空。
在这里插入图片描述
思路:
1.将字符串转为数组
2. 定义双指针,如果fast上的元素,不等于#,就覆盖slow位置上的值
3. 如果等于#,就让slow自减
4. 然后每个都求省略后的元素,然后isequal就好了

class Solution {
    public boolean backspaceCompare(String s, String t) {
        char[] chs1 = s.toCharArray();
        char[] chs2 = t.toCharArray();
        return solve(chs1).equals(solve(chs2));
    }

    private String solve(char[] chs) {
        /*
        双指针模拟退格
         */
        int len = chs.length;
        int slow = -1, fast = 0;
        while (fast < len) {
            if (chs[fast] != '#') {
                // 普通字母直接统计
                chs[++slow] = chs[fast];
            } else {
                // 遇到#考虑退格(注意slow只统计非#的字符,并不会覆盖掉fast)
                if (slow >= 0) slow--;
            }
            fast++;
        }
        // slow位索引就是最后一个字母位置,索引+1就是个数->生成String
        return new String(chs, 0, slow + 1);
    }
}

977. 有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方组成的新数组,要求也按 非递减顺序 排序
在这里插入图片描述
思路:双指针-----一个在头,一个在尾,当头<=尾是,进行一系列比较

class Solution {
    public int[] sortedSquares(int[] nums) {
        /*
        // 暴力遍历法
        for(int i=0;i<nums.length;i++){
            nums[i] = nums[i]*nums[i];
        }
        Arrays.sort(nums);
        return nums;
        */
        // 双指针法(始终法)
        int right = nums.length - 1;
        int left = 0;
        int[] result = new int[nums.length];
        int index = result.length - 1;
        while (left <= right) {
            if (nums[left] * nums[left] > nums[right] * nums[right]) {
                result[index--] = nums[left] * nums[left];
                ++left;
            } else {
                result[index--] = nums[right] * nums[right];
                --right;
            }
        }
        return result;

    }
}

题目【滑动窗口】

  • 滑动窗口:不断调节子序列的起始位置和终止位置,得到想要的结果(是一种双指针法)
  • O(n^2)------> O(n)

209 长度最小的子数组【中等】

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

在这里插入图片描述
思路:窗口内是什么?满足其和 ≥ s 的长度最小的连续子数组
如何移动窗口的起始位置?如果当前窗口的值大于s了,窗口就要向前移动
如何移动窗口的结束位置?窗口的结束位置就是遍历数组的指针

在这里插入图片描述
为什么复杂度是O(n)?
不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)

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 = sum + nums[right];
            // 使用while,每次更新left,并不断比较子序列是否符合条件
            while(sum >= target){
                result = Math.min(result,right-left+1);
                sum = sum - nums[left++]; // 不断变动left
            }

        }
        // 如果result没有赋值的话,就返回0,说明没有符合条件的子序列
        return result == Integer.MAX_VALUE?0:result;

    }
}

904. 水果成篮【中等】

76. 最小覆盖子串【困难】

题目【螺旋矩阵】

59. 螺旋矩阵 II

循环不变量: 左闭右开
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

在这里插入图片描述

class Solution {
    public int[][] generateMatrix(int n) {
        int loop = 0;  // 控制循环次数
        int[][] res = new int[n][n];
        int start = 0;  // 每次循环的开始点(start, start)
        int count = 1;  // 定义填充数字
        int i, j;

        while (loop++ < n / 2) { // 判断边界后,loop从1开始
            // 模拟上侧从左到右
            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;
    }
}

54.螺旋矩阵

29.顺时针打印矩阵

总结

参考的代码随想录进行的相关学习 https://programmercarl.com/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值