跟着Datawhale重学数据结构与算法(2)———数组知识

数组定义

数组是一种数据结构,用于存储一系列相同类型的元素。在大多数编程语言中,数组中的每个元素都有一个索引,通常从0开始。

数组的特点

  • 固定大小:一旦定义,数组的大小通常是固定的,不能动态增减。
  • 相同数据类型:数组中的所有元素应具有相同的数据类型。
  • 元素索引:数组中的元素可以通过索引快速访问。

数组的应用

数组可以用于存储数据列表,如用户输入的数据、文件中的数据行等。常见的应用场景包括:

  • 数据收集
  • 排序和搜索操作
  • 实现其他数据结构,如堆栈和队列

在C++中,你可以这样定义一个数组:

#include <iostream>
using namespace std;

int main() {
    int myArray[5] = {10, 20, 30, 40, 50};
    return 0;
}

随机访问数据元素

你可以通过索引来随机访问数组中的任何元素。索引通常从0开始。例如,访问上面数组的第三个元素:

cout << "第三个元素: " << myArray[2] << endl;

多维数组

二维是个矩阵(数表),以此类推。

数组基本操作

基本操作
访问
查找
修改
插入
删除

首先访问元素:

访问元素
正因为数组的连续存储,所以索引其实就是内存地址的偏移量,首个元素的地址偏移量为0,因此用数组来随机访问元素也非常的高效,直接索引即可,时间复杂度为O(1).
举个例子,把这几个操作都实现一遍(Cpp)
首先,我们需要一个基础数组来展示这些操作:

#include <iostream>
using namespace std;

int main() {
    int myArray[10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    return 0;
}
查找元素
int target = 50;
bool found = false;
for (int i = 0; i < 10; i++) {
    if (myArray[i] == target) {
        cout << "元素 " << target << " 在数组的位置: " << i << endl;
        found = true;
        break;
    }
}
if (!found) {
    cout << "元素 " << target << " 不在数组中" << endl;
}
修改元素
myArray[4] = 55;  // 将数组第五个元素修改为 55
cout << "修改后的第五个元素: " << myArray[4] << endl;
插入元素

方法1:

/* 在数组的索引 index 处插入元素 num */
void insert(int *nums, int size, int num, int index) {
    // 把索引 index 以及之后的所有元素向后移动一位
    for (int i = size - 1; i > index; i--) {
        nums[i] = nums[i - 1];
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num;
}
  • 但是由于数组空间是固定的,如果插入会导致尾部元素的丢失。以此动态数组很好地解决了这个问题。简单介绍一下vector容器,它属于标准模板库(STL)的一部分。vector可以被视为一个能够存储任意类型数据的动态数组。与普通数组相比,vector的大小可以动态改变,可以随机访问元素,还可以在内部自动处理内存分配和释放。当添加的元素超过当前分配的容量时,vector会自动重新分配更大的内存空间来存储更多的元素。
  • cpp中一般使用vector容器进行动态删除插入修改更加方便.
#include <vector>
vector<int> myVector = {10, 20, 30, 40, 50};
myVector.insert(myVector.begin() + 3, 35);  // 在索引3的位置插入35
删除元素

方法1:

/* 删除索引 index 处的元素 */
void remove(int *nums, int size, int index) {
    // 把索引 index 之后的所有元素向前移动一位
    for (int i = index; i < size - 1; i++) {
        nums[i] = nums[i + 1];
    }
}

方法2:

myVector.erase(myVector.begin() + 4);  // 删除索引4的元素

基础知识就介绍到这里,都非常简单。

开始今天的Leetcode之旅~:

【1】 66.加1

class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        int len = digits.size();
        for (int i = len - 1; i >= 0; i--) {
            // 当前位置加一
            digits[i]++;
            // 检查是否需要进位
            if (digits[i] < 10) {
                // 如果不需要进位,直接返回
                return digits;
            }
            // 如果需要进位,设置当前位为0,并在下一轮循环增加上一位
            digits[i] = 0;
        }

        // 如果所有的位都处理完了还有进位,说明是类似999+1这种情况
        vector<int> ans(len + 1);
        ans[0] = 1; // 进位后第一位为1,其余位默认为0
        return ans;
    }
};
  • 整体思路非常简单,就直接在原数组上进行修改,从后往前遍历,就顺着题目的思路,首先最后一位加一,然后判断是否需要进位,不需要就直接返回了。需要进位它最高是0,你就直接赋0就行了,就继续循环往前,到第一位的时候,如果需要进位,你就使用vector容器给数组前面加一位1就行了。

【2】0724. 寻找数组的中心下标

这道题看完直接给我笑😀~太简单了,直接从左往右减判断是否相等。

class Solution {
public:
    int pivotIndex(vector<int>& nums) {
    int totalSum = 0;
        for (int num : nums) {
            totalSum += num;
        }
        int leftSum = 0;
        for (int i = 0; i < nums.size(); ++i) {
            // 右侧和可以由总和减去左侧和再减去当前元素得到
            if (leftSum == totalSum - leftSum - nums[i]) {
                return i;
            }
            leftSum += nums[i];
        }

        return -1;
    }
};
  • 分两步:
  • step1:计算总和:首先通过一个循环计算数组nums的总和totalSum。
    检查中心下标:接着,我们再次遍历数组,这次计算左侧和leftSum。
  • step2:对于每个元素,我们检查左侧和是否等于总和减去左侧和再减去当前元素的值(即右侧和)。如果相等,当前下标就是中心下标。

【3】0189. 轮转数组

用cpp的反转函数reserve其实很容易实现,但是不用这个函数怎么实现呢,我的思路是:开辟一个动态数组,首先一个循环记录k之后的放在vector中,再一个循环记录k之前的,依次下标索引放入vector中。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n=nums.size();
        vector<int> res(n);
        k = k%n;//取长的的模,防止出界
        int flag=0;//原数组从前往后的索引
        for(int i=k;i<n;i++){
            res[i] = nums[flag++];
        }
        for(int j=0;j<k;j++){
            res[j]=nums[flag++];
        }
        nums = res;
        return;

    }
};

perfect!!!代码很简单了,相信大家都能看懂。

【4】0048. 旋转图像

这道题有个投机的方法,你观察这个不就是矩阵先转置再反转行吗,so:

#include <vector>
#include <algorithm>
using namespace std;

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n = matrix.size();
        // 转置
        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                swap(matrix[i][j], matrix[j][i]);
            }
        }
        // 反转行
        for (int i = 0; i < n; i++) {
            reverse(matrix[i].begin(), matrix[i].end());
        }
    }
};

【5】0054. 螺旋矩阵

思路就是,层层递进,逆时针访问完当前边界,然后更新边界位置,缩小范围,进入下一层。这里解释一下代码里的push_back是vector里面的一个成员函数,他的作用是向动态数组的末尾添加元素。遵循上->右->下->左的操作顺序就行。
另外vector还有很多好用的成员函数:

size():返回向量中元素的个数。 empty():检查向量是否为空,如果为空则返回 true,否则返回 false。
clear():清空向量中的所有元素。 resize():改变向量的大小,可以增加或减少元素的数量。
reserve():预留存储空间,但不改变向量的大小。 push_back():向向量末尾添加一个元素。
pop_back():删除向量末尾的元素。 insert():在指定位置插入一个或多个元素。
erase():删除指定位置或指定范围内的元素。 begin():返回一个指向向量第一个元素的迭代器。
end():返回一个指向向量最后一个元素之后位置的迭代器。 front():返回向量第一个元素的引用。
back():返回向量最后一个元素的引用。 at():返回指定位置的元素的引用,带有边界检查。
operator[]:返回指定位置的元素的引用,不带边界检查。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if (matrix.empty()) return {};

        int rows = matrix.size(), cols = matrix[0].size();//获取矩阵的行数和列数
        vector<int> spiral;//生成最后的答案矩阵
        int top = 0, bottom = rows - 1, left = 0, right = cols - 1;//定义四个边界
        while (top <= bottom && left <= right) {//定义顶部边界小于底部边界,左侧边界小于右侧边界时
            // 从左到右遍历顶部行
            for (int i = left; i <= right; ++i) {
                spiral.push_back(matrix[top][i]);
            }
            ++top;
            // 从上到下遍历右侧列
            for (int i = top; i <= bottom; ++i) {
                spiral.push_back(matrix[i][right]);
            }
            --right;
            if (top <= bottom) {
                // 从右到左遍历底部行
                for (int i = right; i >= left; --i) {
                    spiral.push_back(matrix[bottom][i]);
                }
                --bottom;
            }
            if (left <= right) {
                // 从下到上遍历左侧列
                for (int i = bottom; i >= top; --i) {
                    spiral.push_back(matrix[i][left]);
                }
                ++left;
            }
        }
        return spiral;
    }
};

【6】498.对角线遍历

这个题其实和上一道题差不多,上一个四个方向,这道题两个方向,一个向上一个向下,那么我们就来个变量记录方向就行。
其次对角线个数为m+n-1
然后就开始遍历,每次遍历完改变方向。

class Solution {
public:
    vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
        if (mat.empty() || mat[0].empty()) return {};

        int m = mat.size(), n = mat[0].size();//获取行和列数
        vector<int> result;//存放结果
        /*上面的先列好*/
        bool up = true; // 标记当前遍历方向

        for (int sum = 0; sum < m + n - 1; ++sum) {//对角线数为m+n-1
            if (up) {
                // 对角线向上遍历
                for (int i = min(sum, m - 1); i >= 0 && sum - i < n; --i) {
                    result.push_back(mat[i][sum - i]);
                }
            } else {
                // 对角线向下遍历
                for (int i = max(0, sum - n + 1); i < m && sum - i >= 0; ++i) {
                    result.push_back(mat[i][sum - i]);
                }
            }
            up = !up; // 每次遍历方向切换
        }
        return result;
    }
};

今天就敲到这,太累了今天,线代今天的任务还没做完好焦虑。

参考:
[1] 【教程地址 】[电子网站]
[2]Hello 算法教程

感谢:DataWhale社区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/554377.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机数据恢复—KVM虚拟机磁盘文件数据恢复案例

虚拟化数据恢复环境&故障&#xff1a; KVM是Kernel-based Virtual Machine的简称&#xff0c;是一个开源的系统虚拟化模块&#xff0c;自Linux2.6.20版本之后集成在Linux的各个主要发行版本中。KVM使用Linux自身的调度器进行管理。 本案例中的服务器操作系统为Linux&#x…

官宣|Apache Paimon 毕业成为顶级项目,数据湖步入实时新篇章!

北京时间 2024 年 4 月 16日&#xff0c;开源软件基金会 Apache Software Foundation&#xff08;以下简称 ASF&#xff09;正式宣布 Apache Paimon 毕业成为 Apache 顶级项目(TLP, Top Level Project)。经过社区的共同努力和持续创新&#xff0c;Apache Paimon 在构建实时数据…

【剪映专业版】10时间线工具:主轨磁吸、自动吸附、联动、预览轴、全局缩放预览

视频课程&#xff1a;B站有知公开课【剪映电脑版教程】 主轨&#xff1a;有封面标志的轨道才是主轨。 主轨磁吸&#xff1a;开启后&#xff0c;在主轨上移动素材&#xff0c;自动向前磁吸&#xff0c;在其他轨道上移动无此效果&#xff1b;关闭后&#xff0c;不自动向前磁吸&…

艾迪比皮具携手工博科技SAP ERP公有云,打造数字化转型新标杆

4月1日&#xff0c;广州市艾迪比皮具有限公司&#xff08;以下简称“艾迪比”&#xff09;SAP S/4HANA Cloud Public Edition&#xff08;以下简称“SAP ERP公有云”&#xff09;项目正式启动。双方项目组领导、成员出席本次项目启动会&#xff0c;为未来项目的顺利实施打下坚实…

Python程序设计 元组和集合

教学案例七 元组和集合 1. 根据年月日计算周几 根据输入的年号、月号、日号&#xff0c;计算是周几(中文、英文) 蔡勒公式 通过蔡勒&#xff08;Zeller&#xff09;公式可计算星期几 w:星期; w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六 c&…

【hive】lateral view侧视图

文档地址&#xff1a;https://cwiki.apache.org/confluence/display/Hive/LanguageManualLateralView 1.介绍2.语法3.code demo1&#xff09;单重侧视图2&#xff09;多重侧视图3&#xff09;tips&#xff1a;lateral view outer 1.介绍 lateral view也叫侧视图&#xff0c;属…

【electron3】electron将数据写入本地数据库

安装 yarn add sqlite3 --save连接并调用数据库&#xff0c;创建表 createDB.ts文件内容 const sqlite3 require(sqlite3) const NODE_ENV process.env.NODE_ENV const path require(path) const { app } require(electron) let DB_PATH path.join(app.getAppPath(), /…

LDF、DBC、BIN、HEX、S19、BLF、asc、csv、ARXML、slx等(未完待续)

文章目录 如题如题 LDF是LIN报文格式文件,把这个直接拖到软件里面,可以发报文和接收报文 DBC是CAN报文格式文件,把这个直接拖到软件里面,可以发报文和接收报文 BIN文件烧录在BOOT里面(stm32),有人喜欢叫固件,这个固件就是bin文件,bin文件比hex文件体积小 其实BOOT也…

Android apk包使用360加固工具的加固步骤

1&#xff0c;准备好已经签名打包的apk包。 2&#xff0c;在360加固官方网站下载加固exe软件。三六零天御-企业移动应用安全一站式服务平台 3&#xff0c;步骤一&#xff0c;添加加固包&#xff0c;进行加固&#xff0c;并输出加固包&#xff1a; 4&#xff0c;步骤二&#…

预算不足千元SSL证书该怎么选?

随着互联网安全概念日渐深入人心&#xff0c;越来越多的企业或个人为自己的网站加装SSL证书&#xff1b;那对于个人或者小小微企业&#xff0c;预算不足千元的情况下该怎么选择SSL证书呢&#xff1f;可以从以下几个方面进行考量&#xff0c;以确保在有限的预算内获得满足基本安…

Linux编辑器-vim的使用

vim的基本概念 vim的三种模式(其实有好多模式&#xff0c;目前掌握这3种即可),分别是命令模式&#xff08;command mode&#xff09;、插 入模式&#xff08;Insert mode&#xff09;和底行模式&#xff08;last line mode&#xff09;&#xff0c;各模式的功能区分如下&#…

苹果开发初学者指南:Xcode 如何为运行的 App 添加环境变量(Environmental Variable)

概览 Xcode 15 在运行 SwiftUI 代码时突然报告如下警告&#xff1a; Error: this application, or a library it uses, has passed an invalid numeric value (NaN, or not-a-number) to CoreGraphics API and this value is being ignored. Please fix this problem. 不仅如此…

李沐45_SSD实现——自学笔记

主体思路&#xff1a; 1.生成一堆锚框 2.根据真实标签为每个锚框打标(类别、偏移、mask) 3.模型为每个锚框做一个预测(类别、偏移) 4.计算上述二者的差异损失&#xff0c;以更新模型weights 先读取一张图像。 它的高度和宽度分别为561和728像素。 %matplotlib inline import …

NVM下载、NVM配置、NVM常用命令

NVM(nodejs版本管理切换工具)下载、配置、常用命令 0、NVM常用命令 nvm off // 禁用node.js版本管理(不卸载任何东西) nvm on // 启用node.js版本管理 nvm install <version> // 安装node.js的命名 version是版本号 例…

良友:献上今天(打开心窗说亮话)- 沟通篇

目录 一 二 三 四 五 六 七 八 九 十 十一 十二 十三

【Python小游戏】植物大战僵尸的实现与源码分享

文章目录 Python版植物大战僵尸环境要求方法源码分享初始化页面&#xff08;部分&#xff09;地图搭建&#xff08;部分&#xff09;定义植物类 &#xff08;部分&#xff09;定义僵尸类&#xff08;部分&#xff09;游戏运行入口 游戏源码获取 Python版植物大战僵尸 已有的植…

vscode调试文件(C++,ROS和cmake文件)

VsCode调试文件 参考文档&#xff1a; code.visualstudio.com/docs/editor/variables-reference code.visualstudio.com/docs/editor/tasks 主要修改task.json下的"args"、launch.json中的"program",“args” 注意task.json中的label以及launch.json中…

OpenCV 学习笔记2 C++

1.图像直方图 直方图&#xff08;Histogram&#xff09;是图像处理中常用的工具&#xff0c;它表示图像中每个像素强度值的分布情况。在OpenCV中&#xff0c;可以使用 cv::calcHist 函数来计算图像的直方图。 图像直方图是一种展示图像像素强度分布的统计图表。它显示了图像中…

市场份额第一!博睿数据持续领跑中国APM市场

近日&#xff0c;全球领先的IT市场研究和咨询公司IDC发布《中国IT统一运维软件产品市场跟踪报告&#xff0c;2023H2》。报告显示&#xff0c;2023下半年博睿数据以 17.6%的市场份额蝉联 APM(应用性能监控)市场第一。2023年全年博睿数据以18.8%的市场份额持续领跑中国APM市场。 …

实现联系人前后端界面,实现分页查询04.15

实现联系人前后端界面&#xff0c;实现分页查询项目包-CSDN博客 项目结构 数据库中建立两个表&#xff1a; 完整的后端目录 建立联系人People表&#xff0c;分组Type表&#xff0c;实现对应实体类 根据需求在mapper中写对应的sql语句 查询所有&#xff0c;删除&#xff0c;添…
最新文章