代码随想录Day01|数组|704.二分查找、27.去除元素、977.有序数组的平方


代码随想录开源LeetCode题单:代码随想录


一、数组基础

  1. 概念:数组是存放在连续空间上的相同类型数据的集合。
  2. 数组中每个元素都有一个特定的位置编号(从0开始),称之为索引(Index)。
  3. 数组元素索引的最大值 = 数组长度 - 1
  4. 存储空间
    Java语言的存储空间分为栈空间和堆空间,数据类型分为基本数据类型和引用数据类型两种,数组属于引用数据类型
    其中,基本数据类型在栈中直接存储对象的值;而引用数据类型在栈中存储的是对象的引用(内存地址),在对空间中通过引用找到对象的值。
    Java基本类型与引用类型在存储空间上的不同

二、LeetCode题目

1.LeetCode704

LeetCode704.二分查找

1.1 二分查找算法

二分查找(Binary Search)又叫做折半查找,适用于有序数组。
每次查找都将目标范围缩小至原来的一半。

注意事项
二分法的关键在于查找范围的区间选取与循环条件的对应。
区间为[left, right]时,left == right的区间有意义,while循环判断条件为left <= right
区间为[left, right)时,left == right的区间无意义,while循环判断条件为left < right

下面展示闭区间[left, right]的算法。

算法描述

  1. 初始化左右边界lowhigh
  2. 计算中间位置mid,检查数组下标为mid的元素arr[mid]是否等于目标值。
    • 如果相等,则返回mid.
    • 如果目标值小于arr[mid],则将high移动到mid+1
    • 如果目标值大于arr[mid],则将high移动到mid-1
  3. 重复上述步骤,直到low > high ,此时查找失败。

时间复杂度

  • 平均时间复杂度:O(log n)

  • 最坏时间复杂度:O(log n)

空间复杂度:O(1)

1.2 代码

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

2.LeetCode27

LeetCode27.移除元素

数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖
而两层for循环寻找并元素并一次使用后面的元素覆盖时间复杂度过大,容易超时。
可以考虑使用两个指针(数组下标)分别记录待删元素的位置以及需要填补到待删元素位置的数组元素的值,即算法中常用的双指针法

2.1 快慢指针

2.1.1 思路

定义一个快指针和一个慢指针,慢指针用于指向待删元素的位置,快指针用于寻找填补到待删位置的新元素。

  1. 首先令慢指针slow和快指针fast的下标都为0
  2. 使用for循环,fast0开始遍历整个数组(fast < nums.length)。
    在每次循环中:
    nums[fast] != val,则快指针指向的元素需要保留,用nums[fast]覆盖nums[slow],然后slow后移一位。
    nums[fast] == val,则该元素应被删除,此时不进行操作,fast指针后移继续寻找不等于val的值,slow指针原地等待后续赋值。
  3. fast完成遍历后,slow指向新数组下标最大值的后一位,即为新数组长度。
2.1.2 代码
class Solution {
    public int removeElement(int[] nums, int val) {
        // 快慢指针
        int slow = 0;
        for (int fast = 0; fast < nums.length; fast++) {
            if (nums[fast] != val) {
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }
}

2.2 相向指针

2.2.1 思路

本题的实质要求是将数组中值不为val的元素(查明个数k)放在数组前面的位置,通过输出来检验,只需将前k个元素都覆盖为值不为val的即可,不需要考虑后面,也不需要实现交换。

  1. 定义左右两个指针,令left=0right=nums.length - 1,后需使他们相向移动
    right左移动到从右数值不为val的位置,用于覆盖左边等于val的元素。
  2. while循环遍历数组,条件为left <= right
    nums[left] == val时, left需要被移除,将right覆盖到left,然后right--(表示已经使用了这个元素)。
    nums[left]!= val时, left指向的不需要被移除,直接将left右移动一位(left++),继续检查下一个元素。
    每次left移动后,都需要再检查right所指向的值是否等于val,需要将right左移到从右数值不为val的位置。
  3. left > right,循环结束,此时left就是数组中不等于val的元素的数量k,直接返回left
2.2.2 代码
class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        int right = nums.length - 1;
        
        //将right移到从右数第一个值不为val的位置
        while(right >= 0 && nums[right] == val) right--; 
        
        while(left <= right){
            if(nums[left] == val){
                //将right位置的数覆盖到left位置(输出只看前n个不为val的数)
                nums[left] = nums[right];
                right--;
            }
            left++;
            
            //继续在右侧寻找值不为val的位置
            while(right >= 0 && nums[right] == val) right--;
        }
        return left;
    }
}

3.LeetCode977

LeetCode977.有序数组的平方

3.1 思路

双指针(相向指针)
题目描述nums数组按非递减排序(有正有负),则从两侧到中间绝对值依次减小;
题目要求新数组存储nums数组中元素的平方且非递减,则可从后向前存储从大到小的平方值,即使用两个指针在nums数组从两侧向中间寻找,两指针错位时停止寻找。

3.2 代码
class Solution {
    public int[] sortedSquares(int[] nums) {
        int pre = 0;
        int rear = nums.length - 1;
        int[] result = new int[nums.length];
        int index = nums.length - 1;
        while(pre <= rear){	// 从两侧寻找绝对值较小的数进行平方,存入新数组
            if(Math.abs(nums[pre]) < nums[rear]){
                result[index] = nums[rear] * nums[rear];
                index--;
                rear--;
            } else {
                result[index] = nums[pre] * nums[pre];
                index--;
                pre++;
            }
        }
        return result;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值