力扣刷题笔记:字符串(11)

本文介绍了如何实现字符串转整数(atoi)、字符串相乘、单词翻转、版本号比较、最长子串等算法,涵盖字符串操作、数值转换、字符数组处理和滑动窗口技巧。通过实例解析,探讨了字符串处理中的关键步骤和边界条件处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

8. 字符串转换整数 (atoi)(自动机)

逐位判断,并且考虑各种情况
1、首先去掉头部,包括去掉空格和其他符号,直到碰到加减号或者数字
2、设置正负flag,如果是负号则flag为-1
3、用一个long型的ans从字符串最高位开始记录,一边记录一边乘以10,如果超过范围就返回INT_MAX

class Solution {
public:
    int myAtoi(string s) {
    //各种情况判断
    int flag=1,i;long ans=0;
    for(i=0;i<s.size();i++){
        if(s[i]==' ')
            continue;
        if(s[i]=='-'||isdigit(s[i])||s[i]=='+')
            break;
        else return 0;
    }
    if(s[i]=='-')
        flag=-1;
    if(s[i]=='-'||s[i]=='+')
        i++;      
    for(int j=i;j<s.size();j++) {
        if(isdigit(s[j])) {
            ans=ans*10+(s[j]-'0');
            if(ans>INT_MAX&&flag==1) return INT_MAX;
            if(ans>INT_MAX&&flag==-1) return INT_MIN;
        }
        else break; 
    }   
    return flag*ans;
    }
};

43. 字符串相乘(模拟)

将两个字符串翻转后存储,逐位相乘最后统一处理进位,去除前导0,最后再翻转回来

class Solution {
public:
    string multiply(string num1, string num2) {
        vector<int> A, B;
        int n = num1.size(), m = num2.size();
        for (int i = n - 1; i >= 0; i -- ) A.push_back(num1[i] - '0'); //反向存贮
        for (int i = m - 1; i >= 0; i -- ) B.push_back(num2[i] - '0');
        vector<int> C(n + m);
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                C[i + j] += A[i] * B[j];
        int t = 0;  //存贮进位
        for (int i = 0; i < C.size(); i ++ ) {
            t += C[i];
            C[i] = t % 10;
            t /= 10;
        }
        int k = C.size() - 1;
        while (k > 0 && !C[k]) k -- ;  //去除前导0
        string res;
        while (k >= 0) res += C[k -- ] + '0';  //反转
        return res;
    }
};

151. 翻转字符串里的单词(原地两次翻转+一次遍历)

1、本题要求额外空间复杂度为1,所以使用原地翻转的方法
2、由于翻转后单词本身顺序不变,单词之间的顺序变了,所以采用两次翻转的方法
3、首先对整个字符串翻转,把单词之间的顺序调整正确,其次一次遍历调整单词之内字符的顺序
4、根据要求,去掉开头结尾和单词之间多余的空格,方法是遍历到单词的位置,加上一个空格即可
5、用一个idx记录新的单词的当前索引位置

class Solution {
public:
    string reverseWords(string s) {
        // 反转整个字符串
        reverse(s.begin(), s.end());
        int n = s.size();
        int idx = 0;
        for (int start = 0; start < n; ++start) {
            if (s[start] != ' ') {
                // 填一个空白字符然后将idx移动到下一个单词的开头位置
                if (idx != 0) s[idx++] = ' ';
                // 循环遍历至单词的末尾
                int end = start;
                while (end < n && s[end] != ' ') s[idx++] = s[end++];
                // 反转整个单词
                reverse(s.begin() + idx - (end - start), s.begin() + idx);
                // 更新start,去找下一个单词
                start = end;
            }
        }
        s.erase(s.begin() + idx, s.end());
        return s;
    }
};

165. 比较版本号(一次遍历)

用两个指针进行一次遍历,以小数点为每段结尾,只要比较出大小就返回

class Solution {
public:
    int compareVersion(string version1, string version2) {
        int n1=version1.size(),n2=version2.size(),end=max(n1,n2);
        for(int p1=0,p2=0;p1<end||p2<end;p1++,p2++){
            int v1=0,v2=0;
            while(p1<n1&&version1[p1]!='.')v1=v1*10+version1[p1++]-'0';            
            while(p2<n2&&version2[p2]!='.')v2=v2*10+version2[p2++]-'0';
            if(v1>v2)return 1;
            else if(v1<v2)return -1;
        }
        return 0;
    }
};

179. 最大数(排序)

1、注意排序判断函数必须加static静态调用,返回值必须是bool不能是void
2、判断大小不能用a>b,必须用a+b>b+a
3、使用范围for遍历,结尾输出前判断是否全为0,过特殊用例

    static bool cmp(string a,string b)  {
        return a+b>b+a;
    }
    string largestNumber(vector<int>& nums) {
        vector<string> a;
        string str;
        for(auto i:nums)
            a.push_back(to_string(i));
        sort(a.begin(),a.end(),cmp);
        for(auto i:a)
            str+=i; 
        if(str[0]=='0') str="0";
        return str;
    }

剑指 Offer 45. 最小数(排序)

1、将int型数组逐个转为string类型,再存入string数组。
2、用sort函数对string数组从小到大排序,再逐个加到字符串上返回。

class Solution {
public:
    //必须加上static,没有通过类调用
    static bool cmp(string a,string b){
        return a+b<b+a;
    }
    string minNumber(vector<int>& nums) {
    //转换成字符串排序
    vector<string> res;
    string ans;
    //加入to_string转换函数
    for(auto i:nums) res.push_back(to_string(i));

    //排序时设计字符串比较函数
    sort(res.begin(),res.end(),cmp);

    for(auto j:res) ans+=j;
    return ans;
    }
};

340. 至多包含 K 个不同字符的最长子串(滑动窗口)

给定一个字符串 s ,找出 至多 包含 k 个不同字符的最长子串 T ,输出子串 T 长度。

示例 1:
输入: s = “eceba”, k = 2
输出: 3
解释: 则 T 为 “ece”,所以长度为 3。

示例 2:
输入: s = “aa”, k = 1
输出: 2
解释: 则 T 为 “aa”,所以长度为 2

int func(string s, int k) {
    unordered_map m;
    int maxLen = 0;
    int i = 0; // 快指针
    int j = 0; // 慢指针
    while (i < s.size()) {
        if (m.size() <= k) m[s[i]]++;
        while (m.size() > k) { // 当前区间不满足『至多包含k个不同字符』
            if (--m[s[j]] == 0) {
                m.erase(s[j]);
            }
            ++j; // 慢指针左移
        }
        maxLen = max(maxLen, i - j + 1);
        ++i; // 快指针左移
    }
    return maxLen;
}

344. 反转字符串(双指针)

    void reverseString(vector<char>& s) {
        int n = s.size();
        for (int left = 0, right = n - 1; left < right; ++left, --right) {
            swap(s[left], s[right]);
        }
    }

415. 字符串相加(模拟)

从后往前遍历,用while,只要两个字符串和进位有一个存在就while循环,不够的补0

class Solution {
public:
    string addStrings(string num1, string num2) {
        int i = num1.length() - 1, j = num2.length() - 1, add = 0;
        string ans = "";
        while (i >= 0 || j >= 0 || add != 0) {
            int x = i >= 0 ? num1[i] - '0' : 0;
            int y = j >= 0 ? num2[j] - '0' : 0;
            int result = x + y + add;
            ans.push_back('0' + result % 10);
            add = result / 10;
            i -= 1;
            j -= 1;
        }
        // 计算完以后的答案需要翻转过来
        reverse(ans.begin(), ans.end());
        return ans;
    }
};

438. 找到字符串中所有字母异位词(滑动窗口)

1、找两个字符串是否包含,可以用滑动窗口两个指针遍历
2、至于异位词由于顺序不同,可以将字母存入数组,整体对比数组,数组不带顺序

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int>ans;
        if(p.size()>s.size()||s.size()==0) return ans;
        vector<int>need(128);
        vector<int>windows(128);
        for(char a:p) need[a]++;
        for(int i=0;i<p.size()-1;i++) windows[s[i]]++;
        int l=0,r=p.size()-1;//窗口是[l,r]
        while(r<s.size()) {
            windows[s[r++]]++;
            if(windows==need) ans.push_back(l);
            windows[s[l++]]--;
        }
        return ans;
    }
};

678. 有效的括号字符串(两次遍历)

1、两次遍历,从左到右遍历一遍,用left统计,碰见左括号和*加1,碰见右括号减1
2、从右到左遍历一遍,用right统计,碰见右括号和星加1,碰见左括号减1
3、两次遍历出现一个负数就不是有效的括号字符串

class Solution {
public:
    bool checkValidString(string s) {
        int left = 0, right = 0, size = s.size();
        for(int i = 0; i < size; ++i)
        {
            left  += (s[i] == ')') ? -1 : +1;            //从左向右看左括号能否有效
            right += (s[size-1-i] == '(') ? -1 : +1;     //从右向左看右括号能否有效
            if(left < 0 || right < 0)   return false;
        } 
        return true;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值