《算法基础》字符串算法(五) —— 字符串反转

目录

1、344. 反转字符串

2、2000. 反转单词前缀

3、345. 反转字符串中的元音字母

4、剑指 Offer 58 - I. 翻转单词顺序

5、151. 颠倒字符串中的单词

6、557. 反转字符串中的单词 III

7、541. 反转字符串 II

8、917. 仅仅反转字母

9、7. 整数反转


1、344. 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例:

输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]

提示:

  • 1 <= s.length <= 105
  • s[i] 都是 ASCII 码表中的可打印字符

思路:双指针,直接交换

void reverseString(char* s, int sSize){
    int l = 0;
    int r = sSize - 1;
    while(l < r){
        char t = s[l];
        s[l] = s[r];
        s[r] = t;
        l++;
        r--;
    }
}

2、2000. 反转单词前缀

给你一个下标从 0 开始的字符串 word 和一个字符 ch 。找出 ch 第一次出现的下标 i ,反转 word 中从下标 0 开始、直到下标 i 结束(含下标 i )的那段字符。如果 word 中不存在字符 ch ,则无需进行任何操作。

  • 例如,如果 word = "abcdefd" 且 ch = "d" ,那么你应该 反转 从下标 0 开始、直到下标 3 结束(含下标 3 )。结果字符串将会是 "dcbaefd" 。

返回 结果字符串 。

示例:

输入:word = "abcdefd", ch = "d"
输出:"dcbaefd"
解释:"d" 第一次出现在下标 3 。 
反转从下标 0 到下标 3(含下标 3)的这段字符,结果字符串是 "dcbaefd" 。

提示:

  • 1 <= word.length <= 250
  • word 由小写英文字母组成
  • ch 是一个小写英文字母

思路:找到目标字符的下标,然后再双指针交换

char * reversePrefix(char * word, char ch){
    int len = strlen(word);
    int flag = 0;
    // 找到下标
    for(int i = 0; i < len; i++){
        if(ch == word[i]){
            flag = i;
            break;
        }
    }
    // 双指针交换
    int l = 0;
    while(l < flag){
        char t = word[l];
        word[l] = word[flag];
        word[flag] = t;
        l ++;
        flag --;
    }
    return word;
}

3、345. 反转字符串中的元音字母

给你一个字符串 s ,仅反转字符串中的所有元音字母,并返回结果字符串。

元音字母包括 'a''e''i''o''u',且可能以大小写两种形式出现。

示例:

输入:s = "hello"
输出:"holle"

提示:

  • 1 <= s.length <= 3 * 105
  • s 由 可打印的 ASCII 字符组成

思路:利用前后双指针,当两个指针都指向元音字母时进行交换。

bool isset(char a){
    char s[] = {'a', 'e', 'i', 'o', 'u','A','E','I','O','U'};
    for(int i = 0; i < 10; i++)
        if(a == s[i])
            return true;
    return false;
}

char * reverseVowels(char * s){
    int l = 0;
    int r = strlen(s) - 1;
    while(l < r){
        bool ok1 = isset(s[l]);
        bool ok2 = isset(s[r]);
        if(ok1 && ok2){
            s[l] ^= s[r];
            s[r] ^= s[l];
            s[l] ^= s[r];
            l ++;
            r --;
        }
        else if(ok1)
            r --;
        else if(ok2)
            l ++;
        else{
            l ++;
            r --;
        }
    }
    return s;
}

4、剑指 Offer 58 - I. 翻转单词顺序

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",则输出"student. a am I"。

示例:

输入: "the sky is blue"
输出: "blue is sky the"

说明:

  • 无空格字符构成一个单词。
  • 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
  • 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

思路:以空格为单词间的分隔。

char* reverseWords(char* s){
    int len = strlen(s);
    // 处理空字符串
    if(len == 0)
        return s;
    char* ans = (char*)malloc(sizeof(char) * (len + 1));
    int top = 0;
    int L = 0;  // 左边界
    // 处理空白字符串
    while(s[L] == ' ')
        L++;
    if(L >= len)
        return "";
    int l = len - 1;
    int r = len - 1;
    while(l >= L){  
        while(r >= 0 && s[r] == ' ')
            r--;
        l = r;
        while(l >= 0 && s[l] != ' ')
            l--;
        if(l < 0)
            l = -1;
        for(int i = l + 1; i <= r; i++)
            ans[top++] = s[i];
        ans[top++] = ' ';
        r = l;
    }
    ans[--top] = '\0';
    return ans;
}

5、151. 颠倒字符串中的单词

给你一个字符串 s ,颠倒字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

示例:

输入:s = "the sky is blue"
输出:"blue is sky the"

提示:

  • 1 <= s.length <= 104
  • s 包含英文大小写字母、数字和空格 ' '
  • s 中 至少存在一个 单词

思路:先去除空格,再从后往前遍历保存每个单词。

char * reverseWords(char * s){
    // 去除首空格
    while(*s == ' ')
        s++;
    int len = strlen(s);
    char* ans = (char*)malloc(sizeof(char) * (len+1));
    int top = 0;
    int i = len - 1;
    while(i >= 0){
        while(i >= 0 && s[i] == ' ')
            i--;
        int j = i;
        while(i >= 0 && s[i] != ' ')
            i--;
        for(int k = i + 1; k <= j; k++)
            ans[top++] = s[k];
        if(i >= 0)
            ans[top++] = ' ';
    }
    ans[top] = '\0';
    return ans;
}

6、557. 反转字符串中的单词 III

给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

示例:

输入:s = "Let's take LeetCode contest"
输出:"s'teL ekat edoCteeL tsetnoc"

提示:

  • 1 <= s.length <= 5 * 104
  • s 包含可打印的 ASCII 字符。
  • s 不包含任何开头或结尾空格。
  • s 里 至少 有一个词。
  • s 中的所有单词都用一个空格隔开。

思路:快慢双指针,从前往后遍历,碰到空格就反转。

void reverse(char* s, int l, int r){
    r--; // 当前r位置是空格,所以减一
    while(l < r){
        char t = s[l];
        s[l] = s[r];
        s[r] = t;
        l++;
        r--;
    }
}
char * reverseWords(char * s){
    int len = strlen(s);
    int l = 0;
    int r = 0;
    while(r < len){
        while(s[r] != ' ' && r < len)
            r++;
        reverse(s, l, r);
        l = ++r;
    }
    return s;
}

7、541. 反转字符串 II

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例:

输入:s = "abcdefg", k = 2
输出:"bacdfeg"

提示:

  • 1 <= s.length <= 104
  • s 仅由小写英文组成
  • 1 <= k <= 104

思路:计数,记下前后坐标,进行交换

void swap(char* s, int l, int r){
    while(l < r){
        char t = s[l];
        s[l] = s[r];
        s[r] = t;
        l++, r--;
    }
}
char * reverseStr(char * s, int k){
    int len = strlen(s);
    if(k == 1 || len == 1)
        return s;
    if(len < k){
        swap(s, 0, len - 1);
        return s;
    }
    int cnt = 0;
    int L = 0;
    for(int i = 0; i < len; i++){
        cnt++;
        if(cnt == 2 * k){
            swap(s, L, L + k - 1);
            cnt = 0;
            L = i + 1;
        }
    }
    if(cnt < k){
        swap(s, L, len - 1);
    }
    else if(cnt < 2 * k && cnt >= k){
        swap(s, L, L + k - 1);
    }
    return s;
}

8、917. 仅仅反转字母

给你一个字符串 s ,根据下述规则反转字符串:

  • 所有非英文字母保留在原有位置。
  • 所有英文字母(小写或大写)位置反转。

返回反转后的 s 。

示例:

输入:s = "ab-cd"
输出:"dc-ba"

提示:

  • 1 <= s.length <= 100
  • s 仅由 ASCII 值在范围 [33, 122] 的字符组成
  • s 不含 '\"' 或 '\\'

思路:双指针,先判断是不是字母,如果都是字母就交换

bool check(char ch){
    if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
        return true;
    return false;
}
char * reverseOnlyLetters(char * s){
    int len = strlen(s);
    int l = 0;
    int r = len - 1;
    while(l < r){
        bool ok1 = check(s[l]);
        bool ok2 = check(s[r]);
        if(ok1 && ok2){
            char ch = s[l];
            s[l] = s[r];
            s[r] = ch;
            l++;
            r--;
        }
        else if(ok1){
            r--;
        }
        else{
            l++;
        }
    }
    return s;
}

9、7. 整数反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

示例:

输入:x = 123
输出:321

思路:倒着乘再加。

int reverse(int x){
    if(x <= INT_MIN || x >= INT_MAX) return 0;
    long long ans = 0;
    long long t = x;
    while(t){
        if(ans * 10 > INT_MAX || ans * 10 < INT_MIN) return 0;
        ans = ans * 10 + t % 10; 
        t /= 10;
    }
   
    return ans;
}

文首图片素材取自博客:《算法零基础100讲》(第25讲) 字符串算法(五) - 字符串反转_英雄哪里出来的博客-CSDN博客

你可能感兴趣的:(蓝桥杯,c语言,算法)