草庐IT

代码随想录Day01:数组理论基础、二分查找、移除元素

旺仔喜刷刷 2023-11-21 原文

目录

数组理论基础、二分查找、移除元素

1.数组理论基础

题目建议:了解数组基础,以及数组的内存空间地址

  • 数组是存放在连续内存空间上的相同类型数据的集合
  • 数组的元素是不能删的,只能覆盖:平时删除操作也是依次用后一位覆盖,因为申请且初始化后,存储空间就固定了

验证数组在内存的空间地址是否连续:

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

void test_arr() {			//创建一个3*3的二维数组,并打印内存地址
	int array[3][3] = {
		{1,2,3},
		{4,5,6},
		{7,8,9}
	};
	cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << endl;
	cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2] << endl;
	cout << &array[2][0] << " " << &array[2][1] << " " << &array[2][2] << endl;
};

int main()
{
	test_arr();
}

输出的测试地址:

000000B846EFF668 000000B846EFF66C 000000B846EFF670
000000B846EFF674 000000B846EFF678 000000B846EFF67C
000000B846EFF680 000000B846EFF684 000000B846EFF688

2.Leetcode704.二分查找

题目建议: 掌握704.二分查找,先把 704写熟练,要熟悉 根据 左闭右开,左闭右闭 两种区间规则 写出来的二分法。拓展看一下:35.搜索插入位置34. 在排序数组中查找元素的第一个和最后一个位置

思路:

  • 二分法的前提条件:1.数组为有序数组 2.数组中无重复元素
  • 循环不变量规则区间的定义就是不变量,在while寻找中每一次边界的处理都要坚持根据区间的定义来操作
  • 写二分法,区间的定义一般为两种:左闭右闭即[left, right],或者左闭右开即[left, right)。
方法一 左闭右闭:
//方法一 力扣一次AC
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left =0;
        int right=nums.size()-1;  // 定义target在左闭右闭的区间里,[left, right],根据区间定义让所有元素在该区间内
        while(left <= right){     // 当left==right,区间[left, right]依然有效,所以用 <=   例:[2,2]
            int mid=left + ((right - left) / 2); // 防止溢出 等同于(left + right)/2
            if(nums[mid]>target){
                right=mid-1;      // target 在左区间,所以[left, middle - 1]
            }
            else if(nums[mid]<target){
                left=mid+1;       // target 在右区间,所以[middle + 1, right]
            }		
            else{			     // nums[middle] == target
                return mid;		 // 数组中找到目标值,直接返回下标
            }
        }
        return -1;				//未找到目标值
    }
};
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)
方法二 左闭右开:
//方法二 力扣一次AC
class Solution {
public:
    int search(vector<int>& nums, int target) {
    int left = 0;
    int right = nums.size();      // 定义target在左闭右开的区间里,即:[left, right) 根据区间定义让所有元素在该区间内
    while (left < right){		  // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <  例:[2,2)
       int mid = left + (right-left)/2;// 防止溢出 等同于(left + right)/2
        if (nums[mid] > target){
            right = mid;		// target 在左区间,在[left, middle)中
        }
        else if (nums[mid] < target){
            left = mid + 1;		// target 在右区间,在[middle + 1, right)中
        }
        else{					 // nums[middle] == target
            return mid;			// 数组中找到目标值,直接返回下标
        }
     
    }
    return -1 ;					//未找到目标值
    }					
};
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)
方法三 左开右开:
// 方法三 左开右开 未考虑区间定义,超出内存限制一次
class Solution {
public:
    int search(vector<int>& nums, int target) {
    int left = -1;
    int right = nums.size();
    while (left < right-1){    //这里一定考虑区间是否有意义 例如:(2,3)也是没有意义的
       int mid = left + (right-left)/2;
        if (nums[mid] > target){
            right = mid;
        }
        else if (nums[mid] < target){
            left = mid ;
        }
        else{
            return mid;
        }
     
    }
    return -1 ;
    }
};
方法四 左开右闭:
class Solution {
public:
    int search(vector<int>& nums, int target) {
    int left = -1;
    int right = nums.size()-1;
    while (left < right){
       int mid = ( (left + right + 1) / 2) ;
        if (nums[mid] > target){
            right = mid -1;
        }
        else if (nums[mid] < target){
            left = mid ;
        }
        else{
            return mid ;
        }
     
    }
    return -1 ;
    }
};

3.Leetcode27. 移除元素

题目建议27.移除元素,暴力的解法,可以锻炼一下我们的代码实现能力,建议先把暴力写法写一遍。 双指针法 是本题的精髓,今日需要掌握,至于拓展题目可以先不看。

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

方法一 暴力解法

这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。

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++){	//从i后面一位开始往前移一位
                     nums[j-1]=nums[j];
                 }
                 i--;		// 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                 size--;	// 此时数组的大小-1
            }
           
        }
        return size;
    }
};
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)
方法二 双指针法

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作

双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        int slow = 0;
        for(int i =0;i < size;i++){
            if(nums[i]!=val){
                nums[slow]=nums[i];
                slow++;
            }
        }
        return slow;
    }
};
/**
* 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
* 时间复杂度:O(n)
* 空间复杂度:O(1)
*/
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int leftIndex = 0;
        int rightIndex = nums.size() - 1;
        while (leftIndex <= rightIndex) {
            // 找左边等于val的元素
            while (leftIndex <= rightIndex && nums[leftIndex] != val){
                ++leftIndex;
            }
            // 找右边不等于val的元素
            while (leftIndex <= rightIndex && nums[rightIndex] == val) {
                -- rightIndex;
            }
            // 将右边不等于val的元素覆盖左边等于val的元素
            if (leftIndex < rightIndex) {
                nums[leftIndex++] = nums[rightIndex--];
            }
        }
        return leftIndex;   // leftIndex一定指向了最终数组末尾的下一个元素
    }
};

有关代码随想录Day01:数组理论基础、二分查找、移除元素的更多相关文章

  1. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  2. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  3. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  4. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  5. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  6. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  7. 程序员如何提高代码能力? - 2

    前言作为一名程序员,自己的本质工作就是做程序开发,那么程序开发的时候最直接的体现就是代码,检验一个程序员技术水平的一个核心环节就是开发时候的代码能力。众所周知,程序开发的水平提升是一个循序渐进的过程,每一位程序员都是从“菜鸟”变成“大神”的,所以程序员在程序开发过程中的代码能力也是根据平时开发中的业务实践来积累和提升的。提高代码能力核心要素程序员要想提高自身代码能力,尤其是新晋程序员的代码能力有很大的提升空间的时候,需要针对性的去提高自己的代码能力。提高代码能力其实有几个比较关键的点,只要把握住这些方面,就能很好的、快速的提高自己的一部分代码能力。1、多去阅读开源项目,如有机会可以亲自参与开源

  8. 7个大一C语言必学的程序 / C语言经典代码大全 - 2

    嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来

  9. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  10. 软件测试基础 - 2

    Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功

随机推荐