11.13 LeetCode 题目汇总与解题思路

28. 找出字符串中第一个匹配项的下标

1.1 暴力匹配法(Brute Force)

复制代码
class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size(), m = needle.size();
        for (int i = 0; i + m <= n; i++) {
            bool flag = true;
            for (int j = 0; j < m; j++) {
                if (haystack[i + j] != needle[j]) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                return i;
            }
        }
        return -1;
    }
};

特点:

  • 时间复杂度:O(n×m)
  • 空间复杂度:O(1)
  • 简单直观,但效率低

1.2 KMP算法(无哨兵版 - 推荐)

复制代码
class Solution {
public:
    int strStr(string haystack, string needle) {
        if (needle.empty()) return 0;
        
        int n = haystack.size(), m = needle.size();
        
        // 计算next数组
        vector<int> next(m, 0);
        for (int i = 1, j = 0; i < m; i++) {
            while (j > 0 && needle[i] != needle[j]) {
                j = next[j - 1];  // 关键:循环回退
            }
            if (needle[i] == needle[j]) {
                j++;
            }
            next[i] = j;
        }
        
        // 匹配过程
        for (int i = 0, j = 0; i < n; i++) {
            while (j > 0 && haystack[i] != needle[j]) {
                j = next[j - 1];  // 失配时跳转
            }
            if (haystack[i] == needle[j]) {
                j++;
            }
            if (j == m) {
                return i - m + 1;  // 找到匹配
            }
        }
        
        return -1;
    }
};

1.3 KMP算法(有哨兵版)

复制代码
class Solution {
public:
    int strStr(string haystack, string needle) {
        if (needle.empty()) return 0;
        
        int n = haystack.size(), m = needle.size();
        
        // 添加哨兵
        string s = " " + haystack;
        string p = " " + needle;
        
        vector<int> next(m + 1, 0);
        
        // 计算next数组
        for (int i = 2, j = 0; i <= m; i++) {
            while (j > 0 && p[i] != p[j + 1]) {
                j = next[j];
            }
            if (p[i] == p[j + 1]) {
                j++;
            }
            next[i] = j;
        }
        
        // 匹配过程
        for (int i = 1, j = 0; i <= n; i++) {
            while (j > 0 && s[i] != p[j + 1]) {
                j = next[j];
            }
            if (s[i] == p[j + 1]) {
                j++;
            }
            if (j == m) {
                return i - m;
            }
        }
        
        return -1;
    }
};

KMP核心思想总结

算法流程:

  1. 预处理:计算模式串的next数组
  2. 匹配:利用next数组在失配时智能跳转

关键理解:

  • next[i]:前i个字符的最长公共前后缀长度
  • 失配时 :j = next[j-1](回退到已匹配部分的前缀之后)
  • 主串指针不回溯,保证O(n)时间复杂度

151、反转字符串中的单词

2.1 双指针法(最优解)

复制代码
class Solution {
public:
    string reverseWords(string s) {
        string ans;
        int n = s.size();
        
        for (int i = n - 1; i >= 0;) {
            // 跳过尾部空格
            while (i >= 0 && s[i] == ' ') {
                i--;
            }
            if (i < 0) break;  // 处理全空格情况
            
            int end = i;  // 单词结尾位置
            
            // 找到单词开头
            while (i >= 0 && s[i] != ' ') {
                i--;
            }
            
            // 添加空格(非第一个单词)
            if (!ans.empty()) {
                ans += " ";
            }
            
            // 提取单词 [i+1, end]
            ans += s.substr(i + 1, end - i);
        }
        
        return ans;
    }
};

特点:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)(不包括结果字符串)
  • 原地操作,效率最高

2.2 栈方法

复制代码
class Solution {
public:
    string reverseWords(string s) {
        stack<string> stk;
        int n = s.size();
        int i = 0;

        while (i < n) {
            // 跳过前导空格
            while (i < n && s[i] == ' ') i++;
            
            if (i >= n) break;

            // 找到单词结束位置
            int start = i;
            while (i < n && s[i] != ' ') i++;

            // 提取单词
            string word = s.substr(start, i - start);
            stk.push(word);
        }

        string ans;
        while (!stk.empty()) {
            ans += stk.top();
            stk.pop();
            if (!stk.empty()) ans += ' ';
        }
        return ans;
    }
};

特点:

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
  • 思路清晰,易于理解

2.3 字符串流方法(最简洁)

复制代码
class Solution {
public:
    string reverseWords(string s) {
        stringstream ss(s);
        string word, ans;
        
        while (ss >> word) {
            if (!ans.empty()) ans = " " + ans;
            ans = word + ans;
        }
        
        return ans;
    }
};

特点:

  • 代码最简洁
  • 自动处理空格分割
  • 时间复杂度:O(n),空间复杂度:O(n)

算法对比总结

KMP算法对比:

方法 时间复杂度 空间复杂度 特点
暴力法 O(n×m) O(1) 简单直观,效率低
KMP无哨兵 O(n+m) O(m) 推荐,易于理解
KMP有哨兵 O(n+m) O(m) 代码简洁,边界处理简单

反转单词对比:

方法 时间复杂度 空间复杂度 特点
双指针法 O(n) O(1) 最优解,原地操作
栈方法 O(n) O(n) 思路清晰,易于理解
字符串流 O(n) O(n) 代码最简洁

核心技巧总结

KMP关键点:

  1. next数组计算 :while循环确保完全回退
  2. 失配跳转 :j = next[j-1] 利用已匹配信息
  3. 主串指针不回溯:保证线性时间复杂度

反转单词关键点:

  1. 双指针技巧:一个找单词头,一个找单词尾
  2. 边界处理:正确处理连续空格和边界情况
  3. 字符串拼接 :使用 if (!ans.empty()) 避免开头多余空格
相关推荐
zx_741484811 小时前
YOLOv3 核心原理详解:Darknet-53 架构、多尺度预测与 FPN 特征融合
算法·yolo·目标检测·yolov3
MoRanzhi12031 小时前
122.四平方和(暴力枚举)
python·数学·算法·蓝桥杯·完全平方数·暴力枚举·四平方和定理
倒头就睡的小比特1 小时前
贪心算法介绍
算法·贪心算法
万少1 小时前
Qoder sonus模型 20分钟,复刻 马斯克 飞天汽车
前端·后端·算法
七牛云行业应用2 小时前
Muse Spark Open 发布:Meta 称其为美国最强开放权重模型,816B 参数如何落地
算法
esop轻Mes看板亮灯分拣ESD静电安2 小时前
产线“最后一米”的破局密码:ESOP与MES的区别与深度协同
算法
动词ing2 小时前
[题目练习】三数之和
数据结构
陈天伟教授2 小时前
《数据处理和标注技术》课程能力图谱
人工智能·算法
LMT_Lanmantech2 小时前
HyperWorks许可:almutil显示Unit满了,数据到底准不准?
运维·服务器·算法
YSL0701242 小时前
一文通关-----栈和队列
开发语言·数据结构