leetcode刷题第八天——字符串

本次刷题顺序是按照卡尔的代码随想录中给出的顺序

对于c语言,没有string类型,所以,字符串只能使用char* s的形式来表示

下面用到的库函数,主要有strlen(char* s)和isspace(char ch),第一个是求字符串s的长度,第二个是判断字符ch是否为空字符。

提到字符串,不得不提经典的匹配算法KMP,KMP比暴力算法高效,是因为它维护了next数组,next数组中存储的是当前下标以前的字符串中,最大相等前后缀的长度。这有什么用呢?那必然是,当模式串(假设下标为j)与文本串(下标为i)当前字符不匹配时,使用next[j - 1]处与i处的字符进行匹配……这样子,在当前字符不匹配时,文本串的下标不需要回退,模式串的下标进行回退即可

如果还是不太理解,可以参考下边这篇博客

图解KMP算法,带你彻底吃透KMP-优快云博客

344. 反转字符串

void reverseString(char* s, int sSize) {
    int left = 0, right = sSize - 1;
    char ch;
    while(left < right) {
        ch = s[left];
        s[left] = s[right];
        s[right] = ch;
        left++;
        right--;
    }
}

541. 反转字符串 II

void restr(char* s, int start, int end) {
    int left = start, right = end;
    char ch;
    while(left < right) {
        ch = s[left];
        s[left] = s[right];
        s[right] = ch;
        left++;
        right--;
    }
}
 
char* reverseStr(char* s, int k) {
    int idx = 0, len = strlen(s), end;
    for(idx = 0; idx < len; idx += 2*k) {
        if(len > idx + k - 1) restr(s, idx, idx + k - 1);
        else restr(s, idx, len - 1);
    }
    return s;
}

151. 反转字符串中的单词

/*反转s[start, end]之间的字符*/
void restr(char* s, int start, int end) {
    char ch;
    int left = start, right = end;
    while(left < right) {
        ch = s[left];
        s[left] = s[right];
        s[right] = ch;
        left++;
        right--;
    }
}

/*移除前后和中间多余的空格*/
void RemovESpace(char* s) {
    int left = 0, right = strlen(s) - 1;
    int idx = 0;
    while(isspace(s[left])) left++;
    while(isspace(s[right])) right--;
    while(left <= right) {
        while(isspace(s[left]) && (left + 1 <= right && isspace(s[left + 1]))) left++;
        s[idx++] = s[left++];
    }
    s[idx] = '\0';
}

char* reverseWords(char* s) {
    RemovESpace(s);
    int len = strlen(s);
    restr(s, 0, len - 1);
    int idx = 0, slow = 0;
    while(idx <= len) {//此处,因为什么可以等于?是因为,s[len]处,是字符串的结束标志'\0' 
        if(isspace(s[idx]) || s[idx] == '\0') {
            restr(s, slow, idx - 1);
            slow = idx + 1;
        }
        idx++;
    }
    return s;
}

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

//获取next数组
void GetNext(char* s, int* next, int len) {
    next[0] = 0;
    int j = next[0], i;
    for(i = 1; i < len; i++) {
        /*当j和i指向的字符不相等,并且j还没有回退到0时,j进行回退*/
        while(j > 0 && s[j] != s[i]) j = next[j - 1];
        if(s[j] == s[i]) j++;//当前i,j指向字符相同,则j自增,j表示i处前缀和后缀最大匹配数
        next[i] = j;
    }
    return;
}

int strStr(char* haystack, char* needle) {
    int n_len = strlen(needle), h_len = strlen(haystack);
    int* next = malloc(sizeof(int) * n_len);
    int n_idx = 0, h_idx = 0, cnt = 0;
    GetNext(needle, next, n_len);
    while(h_idx < h_len) {
        if(haystack[h_idx] == needle[n_idx]) {//当前匹配,则两个指针均移动
            h_idx++;
            n_idx++;
            if(n_idx == n_len) return (h_idx - n_idx);//如果匹配完成,则返回下标
        }else {//若当前不匹配,视情况移动needle的指针
            if(n_idx > 0) n_idx = next[n_idx - 1];//如果可以回退,则回退
            else h_idx++;//如果n_idx已经指向0,无法回退,则只能将h_idx自增,再进行下一轮匹配
        }
    }
    return -1;
}

459. 重复的子字符串

//获取next数组
void GetNext(char* s, int* next, int len) {
    next[0] = 0;
    int j = next[0], i;
    for(i = 1; i < len; i++) {
        /*当j和i指向的字符不相等,并且j还没有回退到0时,j进行回退*/
        while(j > 0 && s[j] != s[i]) j = next[j - 1];
        if(s[j] == s[i]) j++;//当前i,j指向字符相同,则j自增,j表示i处前缀和后缀最大匹配数
        next[i] = j;
    }
    return;
}

bool repeatedSubstringPattern(char* s) {
    int len = strlen(s);
    if(len == 0) return false;
    int* next = malloc(sizeof(int) * len);
    GetNext(s, next, len);
    /*当最小重复子串的长度可以被字符串原本长度整除,则说明可以由某个子串重复构建而成*/
    if(next[len - 1] != 0 && len % ( len - next[len - 1]) == 0) return true;
    else return false;    
}

冲冲冲!!!明天开始栈与队列,奥里给

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值