嵌入式学习!(一)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;
}
相关推荐
꧁细听勿语情꧂4 分钟前
向下调整算法,top - k 问题,链式结构二叉树,前中后序遍历
c语言·开发语言·数据结构·算法
2301_780943846 分钟前
第三阶段:Gem5-GPU集成学习
学习
~kiss~7 分钟前
quantizers 学习
学习
暖阳之下8 分钟前
学习周报四十二
学习
踩坑记录24 分钟前
leetcode hot100 169. 多数元素 easy 技巧 摩尔投票
leetcode
wubba lubba dub dub75028 分钟前
第四十四周 学习周报
学习
水蓝烟雨28 分钟前
3487. 删除后的最大子数组元素和
算法·leetcode·链表
LG.YDX40 分钟前
笔试训练48天:最长无重复子数组
数据结构·算法
yong99901 小时前
基于灰狼算法优化支持向量回归(GWO-SVR)的混合算法
算法·数据挖掘·回归
sali-tec1 小时前
C# 基于OpenCv的视觉工作流-章53-QR二维码1
图像处理·人工智能·opencv·算法·计算机视觉