代码编织梦想

151.翻转字符串里的单词

识别

这段代码实现了三个字符串处理功能:reverse 用于翻转字符串中指定范围的字符;removeExtraSpace 用于删除字符串两端和中间多余的空格;reverseWords 用于翻转字符串中的单词顺序。

核心/易错

核心功能是字符串的翻转和处理空格。易错点包括:

  • 确保字符串翻转时索引不越界。
  • 正确处理字符串中的空格,避免删除或翻转时出错。

难点/亮点

  • 难点:正确处理字符串中的空格,特别是在单词之间和字符串两端的空格。
  • 亮点reverseWords 函数通过先删除多余空格再翻转单词顺序的方式,实现了单词顺序的翻转,同时保持了单词内部字符的顺序。

算法设计思路

  1. reverse:通过两个指针从两端向中间遍历,交换字符直到两个指针相遇或交错。
  2. removeExtraSpace:首先找到字符串的非空格起始和结束位置,然后遍历字符串,跳过连续的空格,只保留单个空格。
  3. reverseWords:先调用 removeExtraSpace 函数去除多余空格,然后翻转整个字符串,最后遍历翻转后的字符串,翻转每个单词。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 翻转字符串中指定范围的字符
void reverse(char* s, int start, int end) {
    for (int i = start, j = end; i < j; i++, j--) { // 从两端向中间遍历
        int tmp = s[i]; // 交换字符
        s[i] = s[j];
        s[j] = tmp;
    }
}

// 删除字符串两端和中间多余的空格
void removeExtraSpace(char* s) {
    int start = 0; // 指向字符串开头的指针
    int end = strlen(s) - 1; // 指向字符串结尾的指针
    while (s[start] == ' ') start++; // 移动指针 start,直到找到第一个非空格字符
    while (s[end] == ' ') end--; // 移动指针 end,直到找到第一个非空格字符
    int slow = 0; // 指向新字符串的下一个写入位置的指针
    for (int i = start; i <= end; i++) { // 遍历整个字符串
        if (s[i] == ' ' && s[i+1] == ' ') { // 如果当前字符是空格,并且下一个字符也是空格,则跳过
            continue;
        }
        s[slow] = s[i]; // 否则,将当前字符复制到新字符串的 slow 位置
        slow++; // 将 slow 指针向后移动
    }
    s[slow] = '\0'; // 在新字符串的末尾添加一个空字符
}

// 翻转字符串中的单词
char * reverseWords(char * s){
    removeExtraSpace(s); // 先删除字符串两端和中间的多余空格
    reverse(s, 0, strlen(s) - 1); // 翻转整个字符串
    int slow = 0; // 指向每个单词的开头位置的指针
    for (int i = 0; i <= strlen(s); i++) { // 遍历整个字符串
        if (s[i] ==' ' || s[i] == '\0') { // 如果当前字符是空格或空字符,说明一个单词结束了
            reverse(s, slow, i-1); // 翻转单词
            slow = i + 1; // 将 slow 指针指向下一个单词的开头位置
        }
    }
    return s; // 返回处理后的字符串
}

// 主函数,用于测试上述函数
int main() {
    char s[] = "   hello world   ";
    printf("Original: '%s'\n", s);
    char *result = reverseWords(s);
    printf("Reversed: '%s'\n", result);
    return 0;
}

KMP

识别

实现了字符串匹配的两种算法:简单匹配(暴力匹配)和KMP算法。它定义了一个结构体 StrType 来存储字符串及其长度,并提供了相应的函数来分配字符串、执行简单匹配和KMP匹配。

核心/易错

核心功能是字符串匹配,易错点包括内存管理(如正确分配和释放内存)、边界条件处理(如字符串的起始和结束)以及KMP算法中next数组的正确计算。

难点/亮点

  • 难点:KMP算法的next数组计算是理解上的难点,需要正确处理子字符串的前缀和后缀匹配。
  • 亮点:代码结构清晰,将字符串处理和算法逻辑分开,易于理解和维护。

算法设计思路

  1. 简单匹配:通过两个索引分别遍历主字符串和子字符串,逐个字符比较,不匹配则子字符串从头开始重新匹配。
  2. KMP算法:通过预处理子字符串生成next数组,该数组用于在不匹配时调整子字符串的起始比较位置,避免从头开始。(next数组的核心遇见了冲突的位置要向前回退
    子串的最长相等前后缀的长度s[i]!= s[j]即前缀末尾和后缀末尾不匹配的时候
    j为他的前一位的next数组的值同时它也表示前缀的末尾
    B站代码随想录next数组代码17min48)

代码实现

#include <stdio.h>
#include <stdlib.h>

// 定义结构体,用于存储字符串及其长度
typedef struct {
    char *str;
    int length;
} StrType;

// 函数原型声明
int strAssign(StrType *str, const char *ch); // 字符串分配函数
int index_simple(const StrType *str, const StrType *subStr); // 简单匹配函数
int indexKMP(const StrType *str, const StrType *subStr, const int next[]); // KMP匹配函数
void getNext(const StrType *subStr, int next[]); // 计算next数组函数

// strAssign 函数实现,分配内存并复制字符串
int strAssign(StrType* str, const char* ch) {
    if (str->str) {
        free(str->str); // 释放原有内存
    }
    int len = 0;
    while (ch[len]) {
        ++len;
    }
    if (len == 0) {
        str->str = NULL;
        str->length = 0;
    } else {
        str->str = malloc(sizeof(char) * (len + 2)); // 分配内存,+2是为了存储'\0'和可能的扩展
        if (!str->str) {
            return 0; // 内存分配失败
        }
        str->str[0] = '\0'; // 0号索引填充'\0'
        for (int i = 1; i <= len; ++i) {
            str->str[i] = ch[i - 1];
        }
        str->length = len;
    }
    return len;
}

// 简单匹配(暴力匹配)函数实现
int index_simple(const StrType* str, const StrType* subStr) {
    int i = 1; // 主字符串索引
    int j = 1; // 子字符串索引
    while (i <= str->length && j <= subStr->length) {
        if (str->str[i] == subStr->str[j]) {
            ++i;
            ++j;
        } else {
            j = 1; // 重置子字符串索引
            i = (j > 0) ? i + 1 : 1; // 调整主字符串索引
        }
    }
    if (j > subStr->length) {
        return i - subStr->length; // 匹配成功,返回位置
    }
    return 0; // 匹配失败,返回0
}

// KMP算法的next数组计算函数实现
void getNext(const StrType* subStr, int next[]) {
    int i = 1;
    int j = 0;
    next[1] = 0; // 初始化
    while (i < subStr->length) {
        if (subStr->str[i] == subStr->str[j]) {
            ++i;
            ++j;
            next[i] = j;
        } else if (j > 0) {
            j = next[j];
        } else {
            ++i;
        }
    }
}

// KMP算法函数实现
int indexKMP(const StrType* str, const StrType* subStr, const int next[]) {
    int i = 1;
    int j = 1;
    while (i <= str->length && j <= subStr->length) {
        if (j == 0 || str->str[i] == subStr->str[j]) {
            ++i;
            ++j;
        } else {
            j = next[j]; // 根据next数组调整j
        }
    }
    if (j > subStr->length) {
        return i - subStr->length; // 匹配成功,返回位置
    }
    return 0; // 匹配失败,返回0
}

// main 函数实现
int main() {
    StrType str, subStr;
    int next[100]; // 假设next数组足够大

    // 为str和subStr分配字符串
    strAssign(&str, "这是一个示例字符串");
    strAssign(&subStr, "示例");

    // 计算next数组
    getNext(&subStr, next);

    // 使用简单匹配查找子字符串
    int simpleIndex = index_simple(&str, &subStr);
    printf("简单匹配找到子字符串的位置: %d\n", simpleIndex);

    // 使用KMP算法查找子字符串
    int kmpIndex = indexKMP(&str, &subStr, next);
    printf("KMP算法找到子字符串的位置: %d\n", kmpIndex);

    // 释放分配的内存
    free(str.str);
    free(subStr.str);

    return 0;
}

每行代码都添加了注释,以便更好地理解其功能和逻辑。

●卡码网:55.右旋转字符串
●28. 实现 strStr()
●459.重复的子字符串
●字符串总结

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/2301_78809750/article/details/142220703

北京day 16_hxxtcl的博客-爱代码爱编程

今天全场极惨. 在此膜拜某位大佬,简单题不切,只切神题 贴题解 T1 题目大意:有无穷多个卡牌排成一排, 依次编号为 1-N,开始x1,x2,x3……xn正面朝上, 其它的牌反面朝上。每次操作可以选择1个奇质数p , 然后选择连续p张牌, 将其翻转。问将所有牌变为反面朝上的最少操作次数。n<=100,xi<=1e7。 题解:考虑差分,

2021 7.5~7.20日集训总结-爱代码爱编程

Day.1 集训开始的第一天,以数据结构为主体,在之前的基础上进行了不小的扩展。 并查集 启发式合并:一种根据子树大小为基准的合并集合的方式,能够使得“合并集合”操作和“询问”的复杂度降到 O (

牛客国庆集训派对day3 -爱代码爱编程

链接:https://www.nowcoder.com/acm/contest/203/F 来源:牛客网   题目描述 修修在蒜头送给他的奖杯上看到了一个长度为n的字符串s。 他希望从s中选择两个非空子串a,b(可以有重叠的部分),使得它们拼起来是一个回文串。 修修很快就算出了方案数,他听说你也会数数,就让你也来解决一下这个问题。两个方案不同当且仅当a

代码随想录算法训练营day8 | 151.翻转字符串里的单词,卡码网:55.右旋转字符串,28. 实现 strstr(),459.重复的子字符串,字符串总结,双指针回顾-爱代码爱编程

详细布置  151.翻转字符串里的单词 AC 建议:这道题目基本把 刚刚做过的字符串操作 都覆盖了,不过就算知道解题思路,本题代码并不容易写,要多练一练。  题目链接/文章讲解/视频讲解:代码随想录 # 151 # 版本1:全部反转再反转单词 class Solution(object): def revers

代码随想录c++ day8 | 151.翻转字符串里的单词 55.右旋字符串-爱代码爱编程

151.翻转字符串里的单词 最简单的是使用split库函数,分隔单词,然后定义一个新的string字符串,最后再把单词倒序相加。进阶做法是分为三步: 移除多余空格将整个字符串反转将每个单词反转 举个例子,源字符串为:"the sky is blue " 移除多余空格 : "the sky is blue"字符串反转:"eulb si yks eht

算法:按既定顺序创建目标数组-爱代码爱编程

力扣1389 提示: 1 <= nums.length, index.length <= 100nums.length == index.length0 <= nums[i] <= 1000 <= index[i] <= i  题解: class Solution { public int[] cre

day17||654.最大二叉树 |617.合并二叉树 |700.二叉搜索树中的搜索 |-爱代码爱编程

654.最大二叉树 题目:654. 最大二叉树 - 力扣(LeetCode) 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下: 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构建最大二叉树,并且输出这个树的根节点。

<使用生成式ai对四种冒泡排序实现形式分析解释的探讨整理>-爱代码爱编程

<使用生成式AI对四种冒泡排序实现形式分析解释的探讨整理> 文章目录 <使用生成式AI对四种冒泡排序实现形式分析解释的探讨整理>1.冒泡排序实现形式总结1.1关于冒泡排序实现形式1的来

【理论科学与实践技术】数学与经济管理中的学科与实用算法-爱代码爱编程

        在现代商业环境中,数学与经济管理的结合为企业提供了强大的决策支持。包含一些主要学科,包括数学基础、经济学模型、管理学及风险管理,相关的实用算法和这些算法在中国及全球知名企业中的实际应用。 一、数学基础 1). 发现人及著名学者 发现人:欧几里得(Euclid),被称为几何之父。 著名学者:Isaac Newton 和 Gottf

代码随想录算法训练营day9 | 151.翻转字符串里的单词 卡码网:55.右旋转字符串 28. 实现 strstr() -爱代码爱编程

Day9 今天速刷三题,KMP还是挺难 151. Reverse Words in a String 其实不用这么麻烦,但我突发奇想了用这个思路继续往下写了。 class Solution { public:

代码随想录算法训练营day9 |151.翻转字符串里的单词、卡码网:55.右旋转字符串、28. 实现 strstr()的思想(kmp),没写代码-爱代码爱编程

碎碎念:小小题目,轻松拿捏(不是 参考:代码随想录 151.翻转字符串里的单词 题目链接 151.翻转字符串里的单词 思想 首先把字符串全部反转,然后再把里面的单词依次反转,本题还要着重关注删除多余的空格。 使用双

代码随想录训练营day9|151.翻转字符串里的单词,右旋字符串,28. 实现 strstr(),459.重复的子字符串-爱代码爱编程

151.翻转字符串里的单词 思路 1.先将多余空格去除。 2.翻转整个字符串。 3.对单词逐一翻转。 1: int fast=0,slow=0,end=s.size()-1; while(s[fast]==' ')

代码随想录算法营 | day09 | 151.翻转字符串里的单词,卡码网:55.右旋转字符串 字符串一气呵成,kmp后续消化-爱代码爱编程

#算法题目 LeetCode.151.翻转字符串里的单词 题目描述: 给你一个字符串 s ,请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格

代码随想录算法训练营day9|151.翻转字符串里的单词 ,卡码网:55.右旋转字符串,28. 实现 strstr(),459.重复的子字符串,字符串总结,双指针回顾-爱代码爱编程

最近事情较多,博客中断了,每天还在刷题,博客陆续补上。 1、151. 反转字符串中的单词【中等】 给你一个字符串 s ,请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意:输入字符串 s中

代码训练营 day9 | 151.翻转字符串里的单词 | 认识kmp算法-爱代码爱编程

151.翻转字符串里的单词 这道题的难度在于如何高效率的处理空格对于python来说不能实现空间O(1)的复杂度,不过对于其他语言来说下面思路可以 使用双指针方法同时指向数组的头部循环遍历整个字符串直到数组末尾快指针不能为空,因为快指针是要获取字母的,慢指针是用来获取新的字母存放位置的下标判断慢指针是否不为0,因为我们的单词可能在第一个单词前面也有

第九天|字符串| 151.翻转字符串里的单词,卡码网:55.右旋转字符串,28. 实现 strstr(),459.重复的子字符串(kmp算法)-爱代码爱编程

目录 151.翻转字符串里的单词 方法1_fff: 方法2: 方法3: 方法4: 卡码网:55.右旋转字符串 方法1_fff: 方法2: 28. 实现 strStr() 1.KMP算法 什么是KMP 什么是前缀表 最长公共前后缀(最长相等前后缀) 为什么一定要用前缀表 如何计算前缀表 前缀表与next数组 时间复杂度分析