字符串+反转+翻转

字符串在 Python 中是不可变数据类型。如果你对字符串进行任何修改,实际上是创建了一个新的字符串对象,而不是修改原来的字符串。

详细解释:

  • 不可变性: 字符串的不可变性意味着一旦创建了一个字符串对象,它的内容就不能被修改。任何尝试修改字符串的操作,实际上都是在创建一个新字符串,并返回这个新字符串的引用。

  • 创建新副本: 当你对字符串进行“修改”时(例如拼接、切片、替换等操作),Python 实际上会创建一个新的字符串对象,包含修改后的内容,而原来的字符串对象保持不变

1.反转字符串

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        for i in range(len(s)//2):
            s[i], s[len(s)-1-i] = s[len(s)-1-i], s[i]
        return s
class Solution {
public:
    void reverseString(vector<char>& s) {
            for(int i =0;i<(s.size()/2);i++){
                swap(s[i],s[s.size()-1-i]);
            }

    }
};

2.1字符串所有组合

牛客acm模式,给出一个字符串,求出所有字符组合

import sys

for line in sys.stdin:
    line = line.strip()
    arr = [""]
    for i in range(len(line)):
        current_length = len(arr)
        for j in range(current_length):
            new_seq = arr[j] + line[i]
            if new_seq not in arr:
                arr.append(new_seq)
    
    arr.remove("")
    arr = sorted(arr, key=lambda x: (len(x), x))
    print(" ".join(arr))

2.2

输入一个字符串,输出该字符串中相邻字符的所有组合。

import sys

for line in sys.stdin:
    line = line.strip()
    res = []
    index=0
    for i in range(len(line)):
        index += 1
        arr = set()
        for j in range(len(line)-i):
            arr.add(line[j:j+index])
        arr = list(arr)
        arr.sort()
        res+=arr
    print(" ".join(res))

思路:外层循环的i不断增加index并缩小j遍历次数,并增大每次arr.add的元素的长度

3.反转字符串

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        length = len(s)
        count = 0
        s1=[]
        if length<k:
           s1+=(s[length-1::-1]) 
        elif length<2*k and length>=k:
            s1+=(s[k-1::-1])
            s1+=s[k:length]
        else:
            for _ in range(length):
                count += 1
                if count%(2*k)==0:
                    if count==2*k:
                        s1 += s[count-k-1::-1]
                    else:
                        s1 += s[count-k-1:count-2*k-1:-1]
                    s1+=s[count-k:count]
                    if length-count <k:
                        s1+=(s[length-1:count-1:-1])
                    elif length-count<2*k and length-count>=k:
                        s1+=(s[count+k-1:count-1:-1])
                        s1+=s[count+k:length]
        return ''.join(s1)

更加python式的写法

要点s[p:p2]即使最后剩余的元素少于k个,根据切片特性 s[p:p2] 的切片操作不会引发越界错误。相反,它会自动截取从索引 p 开始直到字符串末尾的所有字符。

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        # Two pointers. Another is inside the loop.
        p = 0
        while p < len(s):
            p2 = p + k
            # Written in this could be more pythonic.
            s = s[:p] + s[p: p2][::-1] + s[p2:]
            p = p + 2 * k
        return s
class Solution {
public:
    string reverseStr(string s, int k) {
            for(int i=0;i<s.size();i+=(2*k)){
                if(i+k<=s.size()){
                    reverse(s.begin()+i,s.begin()+i+k);
                }
                else{
                    reverse(s.begin()+i,s.end());
                }
            }
            return s;
    }
};

4.替换数字

lst[i].isdigit()
import sys

line = list(input())
for i in range(len(line)):
    if ord(line[i])-ord('a')>=0 and ord(line[i])-ord('a')<=25:
        pass
    else:
        line[i] = 'number'
print(''.join(line))

思路:先扩充,然后从后往前遍历一但是数字字符,就将number反向加入 

#include <iostream>
using namespace std;
int main() {
    string s;
    while (cin >> s) {
        int sOldIndex = s.size() - 1;
        int count = 0; // 统计数字的个数
        for (int i = 0; i < s.size(); i++) {
            if (s[i] >= '0' && s[i] <= '9') {
                count++;
            }
        }
        // 扩充字符串s的大小,也就是将每个数字替换成"number"之后的大小
        s.resize(s.size() + count * 5);
        int sNewIndex = s.size() - 1;
        // 从后往前将数字替换为"number"
        while (sOldIndex >= 0) {
            if (s[sOldIndex] >= '0' && s[sOldIndex] <= '9') {
                s[sNewIndex--] = 'r';
                s[sNewIndex--] = 'e';
                s[sNewIndex--] = 'b';
                s[sNewIndex--] = 'm';
                s[sNewIndex--] = 'u';
                s[sNewIndex--] = 'n';
            } else {
                s[sNewIndex--] = s[sOldIndex];
            }
            sOldIndex--;
        }
        cout << s << endl;       
    }
}

C++ 中的字符判断

在 C++ 中,字符类型 char 本质上是一个整数类型,可以直接与其他字符或整数进行比较。每个字符都对应一个 ASCII 码值,像 '0''9' 的字符的 ASCII 码值是连续的,因此你可以直接使用比较运算符来判断一个字符是否在某个范围内。

if (s[i] >= '0' && s[i] <= '9') {
    count++;
}

在上面的代码中,s[i] 是一个字符,它会被自动转换为对应的 ASCII 值,然后与 '0''9' 的 ASCII 值进行比较。由于 '0''9' 的 ASCII 值是连续的,这种比较可以有效判断字符是否为数字字符。

Python 中的字符判断

在 Python 中,字符本质上是长度为 1 的字符串对象,字符串的比较依然是基于字符的 Unicode 码点(类似于 ASCII 值)进行的。不过,Python 提供了一些内置函数来处理这些判断任务。

在这种情况下,Python 也会自动将字符与 '0''9' 的 Unicode 码点进行比较,所以这段代码与 C++ 中的代码是等效的。

然而,如果你想直接访问字符的 Unicode 码点,可以使用 ord() 函数,例如:

if '0' <= s[i] <= '9':
    count += 1

if 48 <= ord(s[i]) <= 57:
    count += 1

5.反转字符串

class Solution:
    def reverseWords(self, s: str) -> str:
        s1 = s.split()
        for i in range(len(s1)//2):
            s1[i], s1[len(s1)-i-1] = s1[len(s1)-i-1], s1[i]
        return " ".join(s1)

C++:考虑更多的是去除空格,主要思路是利用快慢指针,快指针先遍历,发现非空并且慢指针不为0说明不是第一个单词了,所以先将慢指针赋一个空,之后再将非空的单词赋给慢指针,这样就实现了单词之间间隔一个空。还有一点很巧妙就是while最后结束时的i和下一次for循环的i差了2,这是因为单词之间要有一个空格所以下一次循环的i指向的是单词结束后的第两位,就是因为单词之间至少会有一个空格,所以跳过这个一定会有的空格,开始判断后面有没有空格。

class Solution {
public:
    void reverse(string& s, int start, int end){ //翻转,区间写法:左闭右闭 []
            for (int i = start, j = end; i < j; i++, j--) {
                swap(s[i], s[j]);
            }
        }
    void removeExtraSpaces(string& s){
        int slow = 0;
        for(int i=0;i<s.size();i++){
            if(s[i]!=' '){
                if(slow!=0) s[slow++]=' ';
                while(i<s.size()&&s[i]!=' '){
                    s[slow++] = s[i++];
                }
            }
        }
        s.resize(slow);
    }
    string reverseWords(string s) {
        removeExtraSpaces(s);
        reverse(s,0,s.size()-1);
        int start=0;
    for(int i=0;i<=s.size();++i){
        if(i==s.size()||s[i]==' '){
            reverse(s,start,i-1);
            start = i+1;
        }
    }
    return s;
    }
};

6.右旋字符串,C++有reverse就很好做,python直接用切片

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    int n;
    string s;
    cin >> n;
    cin >> s;
    int len = s.size();
    reverse(s.begin(),s.end());
    reverse(s.begin(),s.begin()+n);
    reverse(s.begin()+n,s.end());
    cout << s <<endl;
}
import sys

n = int(input())
for line in sys.stdin:
    print(line[len(line)-n:]+line[:len(line)-n])

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

错误代码:没有考虑到回退到哪里。

前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。也就是不用再每次从模式串的头开始匹配了,直接从最长相等前后缀的哪个位置开始继续匹配主串里面的元素,相当于说主串一直遍历,模式串的指针会出现回退。

class Solution {
public:
    int strStr(string haystack, string needle) {
            int lenA = haystack.size();
            int lenB = needle.size();
            if(lenB==0){
                return 0;
            }
            int slow=0;
            for(int i=0;i<lenA;i++){
                if(haystack[i]==needle[slow]){
                        slow++;
                }
                else if(haystack[i]!=needle[slow]){
                    slow=0;
                }
                if(slow==lenB){
                    return i-slow+1;
                }
            }
            return -1;
        }
};

直接暴力,python用切片比较 

class Solution {
public:
    int strStr(string haystack, string needle) {
            int lenA = haystack.size();
            int lenB = needle.size();
            if(lenB==0){
                return 0;
            }
    
            for(int i=0;i<lenA;i++){
                if(haystack.substr(i,lenB)==needle){
                    return i;
                }
            }
            return -1;
    }
};

对于KMP重要的理解就是前缀和后缀:下标5之前这部分的字符串(也就是字符串aabaa)的最长相等的前缀 和 后缀字符串是 子字符串aa ,因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面重新匹配就可以了。

就我个人理解:确定了前缀和后缀的最大公共长度,那么一旦遇到不匹配通过查看next前一个的公共长度就可以回退而不是说从新开始。就比如说上面这张图,遇到f不匹配会回退到下标2这个位置,也就是到了b这个位置重新比较。避免了重复比较。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值