【无标题】

算法day01 数组| 704二分查找/ 27移除元素/ 977有序数组的平方

相关知识

数组

  • 下表从0开始
  • 内存空间的地址是连续的
  • 所以数组元素不能删除只能覆盖, 不能单独删除数组中的某个元素

1. 二分查找 LeetCode 704

题目要求

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

你必须编写一个具有 O(log n) 时间复杂度的算法。

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

提示:

你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。

基本思路

设定target的索引在某一区间内
首先判定targe是否在该数组内
如果在则进行以下步骤:

将区间中点middle 对应的nums制和target进行判定
如果nums[middle] < target, 更新区间的左边界
如果nums[middle] > target, 更新区间的右边界

第一种写法 区间左闭右闭[]

  • 设定target的索引在[left, right] 内
  • [left, right] 左边界可能等于右边界 所以while(left<=right)
    • 该区间范围包含右边界 , 所以right = nums.length-1, 就能够包含target可能的索引
  • 当在 if(nums[middle] > target)时 right = middle -1 因为middle肯定大于target对应的索引
    //  左闭右闭的写法[]
    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 middle = left + (right - left)/2;//需要在每次循环中进行更新
            if(nums[middle] < target){
                //更新左边界
                left = middle + 1;
            }else if(nums[middle] > target){
                right = middle -1;
                //更新右边界
            }else{
                return middle;
            }
        }
        return -1;

第二种写法 左闭右开[)

  • 设定target的索引在[left, right) 内
  • [left, right) 左右肯定不等, 所以while(left < right)
  • 该区间范围不包含右边界 , 所以right = nums.length, 而不是nums.length -1 , 为了区间包含target可能的索引
  • 当在 if(nums[middle] > target)设置右边界的时候 right = middle ** 因为middle肯定大于target对应的索引, 且right不被区间范围包含**
  • ">>"意思是右移一位, 也就是/2
 /**
         **左闭右开的写法[) 不存在[num1, num2)时num1=num2
        */
    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; //索引越界但是它只是一个边界的标记, 也就是不包含该制

        while(left < right){
            int middle = left + ((right - left)>>1); //右移一位
            if(nums[middle] < target){
            //更新左边界
                left = middle + 1;
            }else if(nums[middle] > target){
                //更新右边界
                right = middle;
            }else{
                return middle;
            }

        }
        return -1;
    }

2.移除元素 LeetCode 27

请添加图片描述

双指针法

  • 设定两个指针, fast和slow
  • fast指针用来遍历数组, 寻找新数组的元素
  • slow指针指向的数组下标的位置
  • 将fast指向的元素进行比对, 如果不一致则slow++, 如果一致则slow指向不变, 避开为val的元素
  • 时间复杂度为O(n)
  • 空间复杂度为O(1)
class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0;
        for(int fast = 0 ; fast < nums.length ; fast++ ){
            if(nums[fast] != val){ //慢指针指向不为val的元素
                nums[slow] = nums[fast];
                slow ++;
            }

        }
        return slow;
    }
}

暴力解法 两层for循环

请添加图片描述

  • 外层i 寻找享用值的元素
  • 内层j 讲后续所有元素依次向前移动位\
  • 注意找到后进行i– , 进行再次判断当前i索引的元素, 因为当前i索引的元素已经被覆盖过了, 仍然可能=val
  //暴力解法
    public int removeElement(int[] nums, int val){
        int size = nums.length;
        //第一层寻找等于val的制
        for(int i=0; i<size ; i++ ){
            if(nums[i] == val){
                //第二层 在找到后将之后的索引全部前移动
                for(int j = i ; j<size-1; j++){
                    nums[j] = nums[j+1];

                }
            size--;
            i--; //注意注意

            }

        }
        return size;


    }

3. 有序数组的平方

题目描述

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

示例 1:

  • 输入:nums = [-4,-1,0,3,10]
  • 输出:[0,1,9,16,100]
  • 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]

示例 2:

  • 输入:nums = [-7,-3,2,3,11]
  • 输出:[4,9,9,49,121]

暴力解法

思路
  • 首先遍历一遍数组, 将每个元素平方后重新赋值
  • 利用Arrays.sort(nums)进行升序排序
  • O(n + nlogn)时间复杂度

    public int[] sortedSquares(int[] nums) {
    
        //将全部元素进行平方
    
        int i = 0;
    
        while( i < nums.length){
    
          nums[i] *= nums[i];
    
          i++;
    
        }
    
      Arrays.sort(nums);
    
       return nums;
    
       }
    
注意
  1. nums[i] *= nums[i];即可赋值

双指针法

思路
  • 给出的数组是有序的, 但是平方后的最大值可能会出现在数组两端

  • 设置两个指针i, j.
    i指向起始位置, 从左到右
    j指向终止位置,从右到左

  • 设置新数组result 和新的索引index, 让index指向终止位置

  • 判断:
    如果nums[i]平方>nums[j]平方,则 result[index–] =nums[i]平方,i++, i右移,j不变
    如果nums[i]平方<nums[j]平方,则 result[index–] =nums[j]平方,j–, j左移,i不变


     /**
        1. 双指针法 */
        public int[] sortedSquares(int[] nums) {
            //设定一个新数组, 存储新的排序元素
            //两个指针一个向后, 一个向前
            int index = nums.length-1;
            int[] result = new int [nums.length];
            for(int i = 0, j = nums.length-1; i<=j;){
                int squarei = nums[i] * nums[i];
                int squarej = nums[j] * nums[j];
                
                if(squarei>squarej){
                     //如果i对应的元素大于j对应的元素, 则将i对应的元素存入新数组的j索引处, 然后两个索引都向中间移一位
                    result[index--] = squarei;
                    i++;
                } else{ //如果i对应的元素小于等于j对应的元素, 则将j对应的元素存入新数组的最后,
                    result[index --] = squarej;
                    j--;
    
                }
    
            }
            return result;
        }
注意
  • int i,j连续初始化赋值
  • for(int i = 0, j = nums.length-1; i<=j;)循环中i,j的加减操作写到循环体中,而不在声明中, 更易于控制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值