嵌入式学习!(一)C++学习-leetcode(21)-26/1/29

开始搓题

1、两数之和 = 目标值

利用哈希表key=数值,value=索引

使用目标值减去当前值,然后检测这个数是否再哈希表中?若有则找到:若无则将当前值存入哈希表;

复制代码
vector<int> twoSum(vector<int>& nums, int target) {
    // 创建哈希表,key = 数值,value = 索引
    unordered_map<int, int> mp;
    
    for (int i = 0; i < nums.size(); i++) {
        // 计算所需的另一个数
        int complement = target - nums[i];
        
        // 检查这个数是否已经在哈希表中
        if (mp.find(complement) != mp.end()) {
            // 找到了!返回索引
            return {mp[complement], i};
        }
        
        // 将当前数字和索引存入哈希表
        mp[nums[i]] = i;
    }
    
    // 没找到,返回空数组
    return {};
}

2、最佳时机购买股票

给定一个数组 prices,其中 prices[i] 是第 i 天的股票价格。 你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。

动态规划思想(一次遍历)

记录目前为止的最小价格;记录最大利润

复制代码
// 方案1:动态规划思想(一次遍历)- 最优解
// O(n) 时间,O(1) 空间
int maxProfit_Optimal(vector<int>& prices) {
    // 特殊情况处理
    if (prices.empty()) return 0;
    
    int minPrice = prices[0];  // 记录到目前为止的最小价格
    int maxProfit = 0;         // 记录最大利润
    
    // 从第二天开始遍历
    for (int i = 1; i < prices.size(); i++) {
        // 如果今天卖出,能获得多少利润
        int profit = prices[i] - minPrice;
        
        // 更新最大利润
        maxProfit = max(maxProfit, profit);
        
        // 更新最小价格
        minPrice = min(minPrice, prices[i]);
    }
    
    return maxProfit;
}

3、反转列表

题目:给你单链表的头节点 head,请你反转链表,并返回反转后的链表。

反转前:1 -> 2 -> 3 -> 4 -> 5 -> NULL

反转后:5 -> 4 -> 3 -> 2 -> 1 -> NULL

核心思路:维护三个指针,逐个反转指向关系

步骤:

  1. prev = NULL, curr = head

  2. 循环处理:

  • 保存下一个节点(防止丢失链表)

  • 当前节点指向前一个节点(反转)

  • 三个指针都向前移动

    初始:NULL <- [1] [2] [3] [4] [5]
    prev curr

    第1步:NULL <- [1] [2] [3] [4] [5]
    prev curr

    第2步:NULL <- [1] <- [2] [3] [4] [5]
    prev curr

    第3步:NULL <- [1] <- [2] <- [3] [4] [5]
    prev curr

    ...最终:NULL <- [1] <- [2] <- [3] <- [4] <- [5]
    prev curr(NULL)

    ListNode* reverseList_Iterative(ListNode* head) {
    ListNode* prev = nullptr; // 前一个节点(初始为NULL)
    ListNode* curr = head; // 当前节点

    复制代码
      while (curr != nullptr) {
          // 1. 保存下一个节点(防止丢失)
          ListNode* next = curr->next;
          
          // 2. 反转:当前节点指向前一个节点
          curr->next = prev;
          
          // 3. 向前移动
          prev = curr;
          curr = next;
      }
      
      // prev 现在指向新的头节点
      return prev;

    }

4、两数相加(逆序链表)

题目:给你两个非空的链表,表示两个非负整数。

这些数字以逆序存储在链表中,每个节点包含单个数字。

将这两个数相加,并以链表形式返回一个代表和的链表。

关键点:数字以逆序存储在链表中!

复制代码
链表 [2,4,3] 表示数字 342(逆序!)
链表 [5,6,4] 表示数字 465(逆序!)
相加结果:342 + 465 = 807 → [7,0,8]

核心思想:模拟竖式加法,处理进位

复制代码
    2 4 3
  + 5 6 4
  -------
    7 0 8
  (+ 1 进位)

逆序的好处:从链表头开始就能进行加法运算!

1️⃣  创建虚拟头节点 dummy
    - 简化代码(不需要特殊处理第一个节点)
    - 最后返回 dummy.next 即为真实结果

2️⃣  初始化 carry = 0(进位)

3️⃣  循环处理:
    while (l1 != nullptr || l2 != nullptr || carry != 0)
    
    为什么要检查 carry?
    - 最后两个数相加可能产生进位
    - 例如 [5] + [7] = [2,1],最后的 1 是进位

4️⃣  每次迭代:
    - 获取当前值(NULL 当作 0)
    - 计算 sum = val1 + val2 + carry
    - 新节点值 = sum % 10(个位数)
    - 进位 = sum / 10

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    // 创建虚拟头节点,简化代码
    ListNode* dummy = new ListNode(0);
    ListNode* curr = dummy;
    
    int carry = 0;  // 进位
    
    // 遍历两个链表
    while (l1 != nullptr || l2 != nullptr || carry != 0) {
        // 获取当前节点的值(如果为NULL则为0)
        int val1 = (l1 != nullptr) ? l1->val : 0;
        int val2 = (l2 != nullptr) ? l2->val : 0;
        
        // 计算和
        int sum = val1 + val2 + carry;
        
        // 提取个位数和进位
        int digit = sum % 10;
        carry = sum / 10;
        
        // 创建新节点
        curr->next = new ListNode(digit);
        curr = curr->next;
        
        // 移动指针
        l1 = (l1 != nullptr) ? l1->next : nullptr;
        l2 = (l2 != nullptr) ? l2->next : nullptr;
    }
    
    // 返回结果(跳过虚拟头节点)
    return dummy->next;
}

5、最长不重复子字符串

题目:给定一个字符串 s,请你找出其中不含有重复字符的最长连续子字符串的长度。

**滑动窗口原理:**维护一个"滑动窗口",窗口内没有重复字符

复制代码
字符串:a b c a b c b b
索引:  0 1 2 3 4 5 6 7

第1步:[0,0] = "a"      ✓
第2步:[0,1] = "ab"     ✓
第3步:[0,2] = "abc"    ✓ 长度最大!
第4步:[0,3] = "abca"   ✗ 'a'重复了!左指针移到1
第5步:[1,3] = "bca"    ✓ 
... 继续...
最终:最长长度 = 3

窗口移动规则:

🟢 右指针:一直向右扩展(添加新字符)

🔴 左指针:只有遇到重复时才向右收缩

复制代码
int lengthOfLongestSubstring_Optimal(string s) {
    // 用哈希表存储每个字符最后出现的位置
    unordered_map<char, int> charIndex;
    
    int left = 0;           // 窗口左边界
    int maxLen = 0;         // 最长子字符串长度
    
    // 右指针遍历字符串
    for (int right = 0; right < s.length(); right++) {
        char ch = s[right];
        
        // 如果字符已经存在,且在当前窗口内
        if (charIndex.find(ch) != charIndex.end() && 
            charIndex[ch] >= left) {
            // 左指针移动到重复字符之后
            left = charIndex[ch] + 1;
        }
        
        // 更新字符的最后出现位置
        charIndex[ch] = right;
        
        // 更新最长长度
        maxLen = max(maxLen, right - left + 1);
    }
    
    return maxLen;
}
相关推荐
2501_941322032 小时前
通信设备零部件识别与检测基于改进YOLOv8-HAFB-2算法实现
算法·yolo
modelmd2 小时前
【递归算法】汉诺塔
python·算法
呱呱巨基2 小时前
Linux 第一个系统程序 进度条
linux·c++·笔记·学习
2401_838472512 小时前
C++中的装饰器模式实战
开发语言·c++·算法
白中白121382 小时前
算法题-06
算法
好奇龙猫2 小时前
【人工智能学习-AI入试相关题目练习-第十七次】
人工智能·学习
珍珠是蚌的眼泪2 小时前
LeetCode_二叉树1
leetcode·二叉树·层序遍历·前序遍历·中序遍历·后续遍历
爱学习的阿磊2 小时前
C++与Qt图形开发
开发语言·c++·算法
我材不敲代码2 小时前
机器学习入门02——新手学习的第一个回归算法:线性回归
学习·机器学习·回归