代码随想录Day1 数组基础

2023-09-20 17:58:25

本文详细说明和思路来源于: 

Leetcode T 704

题目链接 704. 二分查找 - 力扣(LeetCode)

题目概述1:

 思路:

1.因为数组是升序排列,且数组的元素不重复,所以使用二分查找法

2.注意区间问题,判断条件是否能遍历所有下标.

写法1:在闭区间[left,right]中

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


        }
         return -1;
        
    }
   
}

写法2:在左闭右开区间[left,right)中

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

思考: 

第一次想到二分查找还可以按照区间来分

第一种:闭区间

假设在nums[7] = {1,3,5,7,9,11,13}中寻找target 7,取值下标范围是[0,6],因为是闭区间,所以right = nums.length - 1,因此left指针是0,right指针是6,这个时候left == right是有意义的,所以结束条件时left <= right,在进行if else判断之前,mid的值已经更新过了,此时进行+1或-1操作即可.

第二种:左闭右开区间

同样是上述条件,这里我们的right指针就得指向nums.length,也就是7,因为这里是开区间,

left == right 是没有意义的,例如判断到 [3,3) 这个时候就是矛盾的,既指向3又不指向3,所以判断条件就是 left < right,当nums[mid]<targrt的时候,也就是说,所求的值可能在mid的右边,所以left = mid + 1,而nums[mid]>target 的时候,就可能在左边,这个时候注意,是把left赋值为mid而不是mid-1,因为是开区间,mid指向的元素是不会参与下一轮循环的判断的.

注:这里的mid之所以取值是left+((right-left)>>1)而不是直接(right-left)>>1或者是(left+right)//2的原因是,因为(left+right)//2中left和right本身是两个int类型的变量,取值范围是-2147483648 ~ 2147483647,而如果出现两个很接近2147483647的数相加时,很容易出现负数;不使用

(right-left)>>1的原因是,本身这个是能表示left和right指针之间的距离的一半,并不能表示mid的下标,而用left加上距离的一半才更好的表示了mid的下标.

总结:

首先是,这题虽然一眼就能看出来使用二分法解决,但是在看到解法之前,我从来没有想过考虑边界的问题,只能举例去慢慢推导出边界,而且很容易犯一些低级错误.现在有所好转.

 题目概述2:

思路: 

这题一开始我已经忘记了,只记得在很久以前做过,是看完了卡哥的题解之后才豁然开朗,所以一道题还是得多刷多总结.

1.暴力求解

两层for循环,一层负责遍历数组,一层负责更新数组,由于数组的删除元素不是真正的删除,而是覆盖掉需要删除的元素,所以时间复杂度是O(n^2),因为一旦发现一个目标元素,就让数组目标元素后面的元素向前移动一位,然后让数组的大小-1.

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        for (int i = 0; i < size; i++) {
            if (nums[i] == val) { // 发现需要移除的元素,就将数组集体向前移动一位
                for (int j = i + 1; j < size; j++) {
                    nums[j - 1] = nums[j];
                }
                i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                size--; // 此时数组的大小-1
            }
        }
        return size;

    }
};

 

 2.快慢指针法

定义一个快指针fast负责寻找目标元素val,一个慢指针负责更新数组,当快指针找到目标元素,即nums[fast] == val,此时慢指针就停下来,直到快指针找到不等于目标值的元素,再对nums[slow] = nums[fast]进行赋值操作.

我们举一个例子:nums[6] = {1,2,3,6,3,9}目标值是3

一开始fast 和 slow指针都指向1,发现不相等,fast和slow都向前走,当指向下标2的时候,fast指针继续向前,slow指针停下,找到下标3发现不相等,就再执行一次赋值,然后两个指针一起向前走,依此往复,最后的数组大小其实就是slow指针指向的下标,因为slow指针再结束后还向后移动了一个单位.最后返回slow的下标即可.

这个解法的时间复杂度只有O(n),因为只遍历了一次数组.

class Solution {
    public int removeElement(int[] nums, int val) {
        int fast = 0;
        int slow = 0;
        for(int i = 0;i<nums.length;i++)
        {
             if(nums[fast] == val)
             {
                 fast++;
             }
             else
             {
                 nums[slow] = nums[fast];
                 fast++;
                 slow++;
             }
        }
        int t = slow;
        return t;

    }
}

 

总结:

需要多训练这种快慢指针解法,多练习,希望这次代码随想录各位都能坚持下去.

更多推荐

Python计算机二级知识点整理

1.当一个进程在运行过程中释放了系统资源后要调用唤醒进程原语唤醒进程原语是把进程从等待队列里移出到就绪队列并设置进程为就绪状态,当一个进程在运行过程中释放了系统资源后进入就绪状态,调用唤醒进程原语。2.3.4.在希尔排序法中,每经过一次数据交换后能消除多个逆序在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数

机械寿命预测(基于NASA C-MAPSS数据的剩余使用寿命RUL预测,Python代码,CNN_LSTM模型,有详细中文注释)

1.效果视频:机械寿命预测(NASA涡轮风扇发动机剩余使用寿命RUL预测,Python代码,CNN_LSTM模型,有详细中文注释)_哔哩哔哩_bilibili环境库版本:2.数据来源:https://www.nasa.gov/intelligent-systems-division数据文件夹数据介绍:当前基于机器学习的

计算机是如何工作的下篇

操作系统(OperatingSystem)操作系统是一组做计算机资源管理的软件的统称。目前常见的操作系统有:Windows系列、Unix系列、Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等.操作系统由两个基本功能:对下,要管理硬件设备.对上,要给软件提供稳定的运行环境.因此,操作系统是软件硬件用户之

【C#】Redis在net core下使用教程

系列文章文章目录系列文章前言一、Redis简介1.1Redis优势1.2Redis与其他key-value存储有什么不同?二、Redis安装步骤2.1下载链接2.2安装测试三、Redis修改帐户密码四、Redis写成Windows服务五、.netcore-使用CSRedisCore操作redis前言官方教程:https

【Azure】构建安全架构的 Azure 云:深入了解零信任体系结构

文章目录前言一、零信任安全模型的概念以及背景介绍二、传统安全模型(边界模型)三、零信任模型(现阶段主流云厂商策略)四、Azure中的零信任体系结构(本文重点)4.1基础知识点(必须了解)(一)Azure中零信任的指导原则(二)Azure中调整为零信任4.2Azure中的零信任体系结构(六层防御)4.3AzureClou

STM32H7 Azure RTOS

STM32H7是意法半导体(STMicroelectronics)推出的一款高性能微控制器系列,基于ArmCortex-M7内核。它具有丰富的外设和高性能计算能力,适用于各种应用领域。AzureRTOS(原名ThreadX)是一款实时操作系统(RTOS),是AzureIoT解决方案的一部分。它是一个可裁剪、可扩展的嵌入

算法通关村第十九关:青铜-动态规划是怎么回事

青铜挑战-动态规划是怎么回事动态规划(简称DP,DynamicProgramming):最热门、最重要的算法之一。面试中大量出现,整体偏难。1.热身:重复计算和记忆化搜索(如何说一万次"我爱你")举例:看谁说更多的我爱你classFibonacciTest:def__init__(self):self.count=0d

MOEA算法的背景知识

MOEA算法多目标进化算法优化MOEA工作原理举个例子为什么单一策略可能会导致种群中的个体过于相似?种群在MOEA里面做什么?举例说明多目标进化算法优化MOEAMulti-objectiveevolutionaryalgorithmoptimization(MOEA)多目标进化算法优化(MOEA)是一种用于解决多目标优

日志审计设计-结合spring-aop实现

日志审计设计设计原则和思路:元注解方式结合AOP,灵活记录操作日志能够记录详细错误日志为运营以及审计提供支持日志记录尽可能减少性能影响操作描述参数支持动态获取,其他参数自动记录。1.定义日志记录元注解,根据业务情况,要求description支持动态入参。例:新增应用{applicationName},其中applic

Linux 文件 & 目录管理

Linux文件基本属性Linux系统是一种典型的多用户系统,为了保护系统的安全性,不同的用户拥有不同的地位和权限。Linux系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定。可以使用命令:ll或ls–l来显示一个文件的属性以及文件所属的用户和组,如图所示:详细解析命令:ls-l中显示的内容使用命令:ll

自定义开发成绩查询小程序

在当今数字化时代,教育行业借助技术手段提高教学效果。作为老师,拥有一个自己的成绩查询系统可以帮助你更好地管理学生成绩,并提供更及时的反馈。本文将为你详细介绍如何从零开始搭建一个成绩查询系统,让你的教学工作更加高效和便捷。不过比较便捷好用的方法还是直接使用现成工具。今天我为大家争取到了易查分的福利,只需要在注册时输入邀请

热文推荐