01.01 数据结构与算法简介、LeetCode 入门及攻略(第 01 ~ 02 天)总结

本文介绍了数据结构中的基本概念,如集合、线性、树形和图形结构,并通过实例解析了LeetCode题目中的两数之和、两整数相加、数组串联、宝石与石头等问题,讨论了不同算法的实现、时间复杂度和空间复杂度分析。
摘要由CSDN通过智能技术生成

数据结构

学习资料:LeetCode 算法笔记
数据结构(Data Structure):带有结构特性的数据元素的集合。

数据结构分类:

  • 按逻辑结构分类
    1. 集合结构 数据元素同属于一个集合,除此之外无其他关系。
    2. 线性结构 数据元素之间是「一对一」关系。 包括数组、链表、以及衍生的栈、队列、哈希表
    3. 树形结构 数据元素之间是「一对多」的层次关系。 包括树、二叉树、多叉树、字典树等
    4. 图形结构 数据元素之间是「多对多」的关系。 包括无向图、有向图、连通图等
  • 按物理结构分类
    1. 顺序存储结构 包括数组
    2. 链式存储结构 包括链表

算法

### 特性

  1. 输入 2. 输出 3. 有穷性 4.确定性 5. 可行性

### 目标

  1. 时间复杂度低 2. 空间复杂度低 3. 正确性 4. 可读性 5. 健壮性

算法复杂度

在问题的输入规模为 n n n的条件下,程序的时间使用情况和空间使用情况。包括**「时间复杂度」「空间复杂度」,用来分析算法执行效率与输入问题规模 n n n的增长关系。通常采用「渐进符号」**的形式来表示「算法复杂度」。

  1. 时间复杂度
  2. 空间复杂度

刷题记录

  1. 两数之和

描述:给定一个整数数组 nums 和一个整数目标值 target

要求:请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。

思路 1:枚举算法
  1. 使用两重循环枚举数组中每一个数 𝑛𝑢𝑚𝑠[𝑖]、𝑛𝑢𝑚𝑠[𝑗],判断所有的 𝑛𝑢𝑚𝑠[𝑖]+𝑛𝑢𝑚𝑠[𝑗] 是否等于 𝑡𝑎𝑟𝑔𝑒𝑡。
  2. 如果出现 𝑛𝑢𝑚𝑠[𝑖]+𝑛𝑢𝑚𝑠[𝑗]==𝑡𝑎𝑟𝑔𝑒𝑡,则说明数组中存在和为 𝑡𝑎𝑟𝑔𝑒𝑡 的两个整数,将两个整数的下标 𝑖、𝑗 输出即可。
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (nums[i] + nums[j] == target) {
                    return {i, j};
                }
            }
        }
        return{};
    }
};
思路 1:复杂度分析
  • 时间复杂度 O ( n 2 ) O(n^2) O(n2),其中 𝑛 是数组 𝑛𝑢𝑚𝑠 的元素数量。
  • 空间复杂度 O ( 1 ) O(1) O(1)
思路 2:哈希表

哈希表中键值对信息为 t a r g e t − n u m s [ i ] : i target-nums[i]: i targetnums[i]:i,其中 i i i 为下标。

  1. 遍历数组,对于每一个数 n u m s [ i ] nums[i] nums[i]
    1. 先查找字典中是否存在 t a r g e t − n u m s [ i ] target - nums[i] targetnums[i],存在则输出 t a r g e t − n u m s [ i ] target - nums[i] targetnums[i] 对应的下标和当前数组的下标 i i i
    2. 不存在则在字典中存入 t a r g e t − n u m s [ i ] target - nums[i] targetnums[i] 的下标 i i i
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> numDict;
        for(int i = 0; i < nums.size(); i++){
            auto it = numDict.find(target - nums[i]);
            if(it != numDict.end())
                return {it->second, i}
            numDict[nums[i]] = i;
        }
        return {};
    }
};
思路 2:复杂度分析
  • 时间复杂度 O ( n ) O(n) O(n),其中 𝑛 是数组 𝑛𝑢𝑚𝑠 的元素数量。
  • 空间复杂度 O ( n ) O(n) O(n)

2235. 两整数相加

描述:给定两个整数 𝑛𝑢𝑚1 和 𝑛𝑢𝑚2。

要求:返回这两个整数的和。

思路 1:直接相加
class Solution {
public:
    int sum(int num1, int num2) {
        return num1 + num2;
    }
};

思路2 :位运算

class Solution {
public:
    int sum(int num1, int num2) {
        while (num2 != 0){
            int temp = num1^num2;
            num2 = (num1&num2) << 1;
            num1 = temp;
        }
        return num1;
    }
};

1929. 数组串联

描述: 给定一个长度为 𝑛 的整数数组 𝑛𝑢𝑚𝑠。

要求:构建一个长度为 2×𝑛 的答案数组 𝑎𝑛𝑠,答案数组下标从 0 开始计数 ,对于所有 0≤𝑖<𝑛 的 𝑖 ,满足下述所有要求:

  • 𝑎𝑛𝑠[𝑖]==𝑛𝑢𝑚𝑠[𝑖]。
  • 𝑎𝑛𝑠[𝑖+𝑛]==𝑛𝑢𝑚𝑠[𝑖]。
class Solution {
public:
    vector<int> getConcatenation(vector<int>& nums) {
        int n = nums.size();
        vector<int> ans(2 * n);
        std::copy(nums.begin(), nums.end(), ans.begin());
        std::copy(nums.begin(), nums.end(), ans.begin() + n);
        return ans;
    }
};

0771. 宝石与石头

描述: 给定一个字符串 𝑗𝑒𝑤𝑒𝑙𝑠 代表石头中宝石的类型,再给定一个字符串 𝑠𝑡𝑜𝑛𝑒𝑠 代表你拥有的石头。𝑠𝑡𝑜𝑛𝑒𝑠 中每个字符代表了一种你拥有的石头的类型。

要求: 计算出拥有的石头中有多少是宝石。

思路一: 类似于两数之和构建hash表

class Solution {
public:
    int numJewelsInStones(string jewels, string stones) {
        unordered_set<char> set;
        int count = 0;
        for(char c : jewels)
            set.insert(c);
        
        for(char c : stones){
            if(set.count(c))
                count++;
        }
        return count;
    }
};

复杂度: 线性时间,常数空间

思路二:位运算 具体思路见 771. 宝石与石头 - 力扣(LeetCode)

class Solution {
public:
    int numJewelsInStones(string jewels, string stones) {
        long long mask = 0;
        for (char c: jewels)
            mask |= 1LL << (c & 63);
            //对于当前字符c,先执行按位与操作(c & 63),获取c的低6位。
            //然后进行右左移操作(mask << ...),将掩码mask左移由(c & 63)确定的位数。
        int ans = 0;
        for (char c: stones)
            ans += mask >> (c & 63) & 1;
            // mask >> (c & 63) 获取c的低6位,将mask右移由(c & 63)确定的位数。
            //最后与1与运算,只保留最低位的值(0或1)。判断c是否在mask中。
        return ans;
    }
};

复杂度: 线性时间,常数空间

1480. 一维数组的动态和

描述:给定一个数组 𝑛𝑢𝑚𝑠。

要求:返回数组 𝑛𝑢𝑚𝑠 的动态和。

说明:动态和:数组前 𝑖 项元素和构成的数组,计算公式为 runningSum[i] = ∑ x = 0 i ( n u m s [ i ] ) \text{runningSum[i]} = \sum_{x=0}^i (nums[i]) runningSum[i]=x=0i(nums[i])

思路一: 累加

class Solution {
public:
    vector<int> runningSum(vector<int>& nums) {
        for(int i = 1; i <nums.size(); i++){
            nums [i] += nums[i-1]; 
        }
        return nums;
    }
};

思路二:STL函数

class Solution {
public:
    vector<int> runningSum(vector<int>& nums) {
        //STL API
        std::partial_sum(nums.begin(), nums.end(), nums.begin());
        return nums;
    }
};

0709. 转换成小写字母

描述:给定一个字符串 𝑠。

要求:将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。

思路一:小写字母比相应大写字母的ASSIC码大32(32而不是26是因为可以直接进行位运算),位运算比’‘加’'更快。

class Solution {
public:
    string toLowerCase(string s) {
        for(char &c : s){
            if (c<='Z' && c>='A')
                c |= 32;
        }
        return s;
    }
};
// 时间复杂度O(n)

思路二:tolower函数

class Solution {
public:
    string toLowerCase(string s) {
        for (char& ch: s) {
            ch = tolower(ch);
        }
        return s;
    }
};
// 时间复杂度O(n)

1672. 最富有客户的资产总量

描述:给定一个 𝑚×𝑛 的整数网格 𝑎𝑐𝑐𝑜𝑢𝑛𝑡𝑠,其中 𝑎𝑐𝑐𝑜𝑢𝑛𝑡𝑠[𝑖][𝑗] 是第 𝑖 位客户在第 𝑗 家银行托管的资产数量。

要求:返回最富有客户所拥有的资产总量。

思路:遍历

class Solution {
public:
    int maximumWealth(vector<vector<int>>& accounts) {
        int MaxWealth = 0;
        for (auto &account : accounts ){
            MaxWealth = std::max(MaxWealth, std::accumulate(account.begin(), account.end(), 0));
        }
        return MaxWealth;
    }
};
// 时间复杂度O(mn)
  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值