LeetCode Day 4:字符串处理

无重复字符的最长子串

问题描述

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

思路关键词:滑动窗口、循环队列

代码实现:

#define MAX_SIZE (129)

// 实现一个循环队列
typedef struct {
    char data[MAX_SIZE];
    int front;
    int rear;
} Queue;

Queue* initQueue() {
    Queue* q = (Queue*) malloc(sizeof(Queue));
    q->front = 0;
    q->rear = 0;
    return q;
}

void enQueue(Queue* q, char c) {
    q->data[(q->rear)++] = c;
    if (q->rear >= MAX_SIZE) {
        q->rear = 0;
    }
}

char deQueue(Queue* q) {
    if (q->front == q->rear) {
        return NULL;
    }
    char ret = q->data[(q->front)++];
    if (q->front >= MAX_SIZE) {
        q->front = 0;
    }
    return ret;
}

int getQueueLength(Queue* q) {
    int ans = q->rear - q->front;
    if (ans < 0) {
        return ans + MAX_SIZE;
    } else {
        return ans;
    }
}

int lengthOfLongestSubstring(char * s){
    Queue* window = initQueue();
    // 存储某个字符上次出现的下标(从1开始)
    int* symbol = (int*) malloc(MAX_SIZE * sizeof(int));
    int symbolIdx = 0;
    int j;
    for (j = 0;j < MAX_SIZE;j++) {
        // 均初始化为-1
        symbol[j] = -1;
    }
    int l = strlen(s);
    // 结果
    int ans = 0;
    int i;
    for (i = 0;i < l;i++) {
        // 查看上一次是否出现
        if (symbol[(int) s[i]] != -1) {
            // 有出现,准备出队
            int oldLen = getQueueLength(window);
            if (oldLen >= ans) {
                ans = oldLen;
            }
            int newIdx = symbol[(int) s[i]] - 1;
            if (newIdx == -1) {
                // 循环队列的特点
                newIdx = MAX_SIZE - 1;
            }
            if ((window->front > window->rear && (newIdx >= window->front || newIdx < window->rear)) ||
            ((window->front < window->rear) && (newIdx >= window->front && newIdx < window->rear))) {
                // 将队头指针移动到该位置
                window->front = newIdx;
                // 出队
                deQueue(window);
            }
        }
        // 入队
        enQueue(window, s[i]);
        // 记录这次的下标+1
        symbol[(int) s[i]] = window->rear;
    }
    int finalLen = getQueueLength(window);
    if (finalLen >= ans) {
        ans = finalLen;
    }
    free(window);
    free(symbol);
    return ans;
}

最长回文子串

问题描述

给你一个字符串 s,找到 s 中最长的回文子串。

思路关键词:动态规划

详细思路:

  • 设置二维动态规划数组 d p ( i , j ) dp(i, j) dp(i,j),表示字符串 s [ i , j ] s[i, j] s[i,j]是不是回文串
  • 状态转移方程: d p ( i , j ) = { t r u e ,    i f   j − i = 0 t r u e ,    i f   j − i = 1   & &   s [ i ] = s [ j ] f a l s e ,    i f   j − i = 1   & &   s [ i ] ≠ s [ j ] d p [ i + 1 ] [ j − 2 ] ,    i f   j − i > 1   & &   s [ i ] = s [ j ] f a l s e ,    i f   j − i > 1   & &   s [ i ] ≠ s [ j ] dp(i, j)=\left\{ \begin{matrix} true, \ \ if\ j-i=0 \\ true, \ \ if\ j-i=1\ \&\&\ s[i]=s[j] \\ false, \ \ if\ j-i=1\ \&\&\ s[i] ≠s[j] \\ dp[i+1][j-2], \ \ if\ j-i >1 \ \&\&\ s[i]=s[j] \\ false, \ \ if\ j-i >1 \ \&\&\ s[i]≠s[j] \end{matrix} \right. dp(i,j)= true,  if ji=0true,  if ji=1 && s[i]=s[j]false,  if ji=1 && s[i]=s[j]dp[i+1][j2],  if ji>1 && s[i]=s[j]false,  if ji>1 && s[i]=s[j]

代码实现如下:

char * longestPalindrome(char * s){
    int l = strlen(s);
    bool** dp = (bool**) malloc(l * sizeof(bool*));
    int i, j;
    for (i = 0;i < l;i++) {
        dp[i] = (bool*) malloc(l * sizeof(bool));
        for (j = 0;j < l;j++) {
            dp[i][j] = false;
        }
    }
    int ansX = 0;
    int ansY = 0;
    for (i = 0; i <= l-1;i++) {
        for (j = 0;j <= l-1-i;j++) {
            if (i == 0) {
                dp[j][j+i] = true; 
                ansX = j;
                ansY = j + i;
            } else if (i == 1) {
                if (s[j] == s[j+1]) {
                    dp[j][j+i] = true;
                    ansX = j;
                    ansY = j + i;
                }
            } else {
                if (s[j] == s[j+i] && dp[j+1][j+i-1] == true) {
                    dp[j][j+i] = true;
                    ansX = j;
                    ansY = j + i;
                }
            }
        }
    }
    char* palind = (char*) malloc((ansY - ansX + 2) * sizeof(char));
    int palindIdx = 0;
    for (i = ansX;i <= ansY;i++) {
        palind[palindIdx++] = s[i];
    }
    palind[palindIdx] = '\0';
    return palind;
}

字符串转换为整数

问题描述

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:
(1)读入字符串并丢弃无用的前导空格
(2)检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
(3)读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
(4)将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
(5)如果整数数超过 32 位有符号整数范围 [−2^31, 2^31 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −2^31 的整数应该被固定为 −2^31 ,大于 2^31 − 1 的整数应该被固定为 2^31 − 1 。
(6)返回整数作为最终结果。
注意:
本题中的空白字符只包括空格字符 ’ ’ 。
除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。

思路关键词:有限状态机(DFA)

代码实现:

bool isDigit(char c) {
    return (c >= '0') && (c <= '9');
}

int myAtoi(char * s){
    /*
        status: 状态机的状态序号
        0:初始状态(--空格-->1, --符号-->2, --数字-->3,--其它-->4)
        1:过滤前导空格(--空格-->1, --符号-->2, --数字-->3,--其它-->4)
        2:读取到符号(--数字-->3,--其它-->4)
        3:读取数字(--数字-->3,--其它-->4)
        4:终止状态(跳出循环)
    */
    int status = 0;
    int sign = 1;
    long ans = 0;
    int idx = 0;
    int l = strlen(s);
    while (1) {
        if (idx == l) break;
        char c = s[idx++];
        if (status == 0) {
            if (c == ' ') {
                status = 1;
            } else if (c == '+') {
                status = 2;
            } else if (c == '-') {
                sign = -1;
                status = 2;
            } else if (isDigit(c)) {
                ans *= 10;
                ans += (c - '0');
                status = 3;
            } else {
                status = 4;
            }
        } else if (status == 1) {
            if (c == ' ') {
                continue;
            } else if (isDigit(c)){
                ans *= 10;
                ans += (c - '0');
                status = 3;
            } else if (c == '+') {
                status = 2;
            } else if (c == '-') {
                sign = -1;
                status = 2;
            } else {
                status = 4;
            }
        } else if (status == 2) {
            if (isDigit(c)) {
                ans *= 10;
                ans += (c - '0');
                status = 3;
            } else {
                status = 4;
            }
        } else if (status == 3) {
            if (isDigit(c)) {
                // 判断越界
                ans *= 10;
                ans += (c - '0');
                if (sign == 1) {
                    if (ans > 2147483647) {
                        ans = 2147483647;
                        status = 4;
                        continue;
                    }
                } else {
                    if (ans > 2147483648) {
                        ans = 2147483648;
                        status = 4;
                        continue;
                    }
                }
                status = 3;
            } else {
                status = 4;
            }
        } else {
            break;
        }
    }
    if (ans == 2147483648) {
        return (-2147483648);
    } else {
        return (sign * ((int) ans));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值