OJ记录册

目录

1、找出字符串中第一个只出现一次的字符

2、字符串相乘

3、反转字符串中的单词 III

4、反转字符串 II

5、字符串相加

6、验证回文串

7、字符串最后一个单词的长度

8、字符串中的第一个唯一字符

9、仅仅反转字母


1、找出字符串中第一个只出现一次的字符

#include <string>
#include <iostream>
using namespace std;

int main()
{
    string words;
    while(cin >> words)
    {
        bool IsFound = false;
        for(int i =0;i<words.size();i++)
        {
            if(words.find_first_of(words[i]) == words.find_last_of(words[i]))
            {
                cout << words.at(i) << endl;
                IsFound = true;
                break;
            }
        }
        if(!IsFound) cout << "-1" << endl;
    }
    return 0;
}
  • find_first_of从前向后找所给字符的位置(作用之一)
  • find_last_of从后向前找所给字符的位置(作用之一)
  • 题解:同时从前和后两个方向寻找同一个字符,找到位置相等则该元素只出现一次,否则该元素在字符串中出现两次

2、字符串相乘

解法一:

#include <string>
class Solution {
public:            //num1是乘数,num2是被乘数
    string multiply(string num1, string num2) {
        if(num1 == "0" || num2 == "0")//一个为0相乘结果为0
            return "0";
        string ans = "0";//初始化存放最终结果的对象
        int m = num1.size() - 1,n = num2.size() - 1;//m和n分别表示乘数和被乘数的下标
        for(int i = n ;i >= 0;i--)//从右向左循环遍历被乘数的每一位
        {   
            string curr;//curr作为每次的结果
            int add = 0;//add存储相乘时进位产生的数值
            for(int j = n;j > i ;j--)//在开始相乘前补零
            {
                curr.push_back(0);
            }
            int y = num2[i] - '0';//获取被乘数下标为i的字符的对应整数
            for(int j = m ;j >= 0;j--)//乘数每一位*被乘数
            {
                int x = num1[j] - '0';//获取乘数下标为j的字符的对应整数
                int product = x * y + add;//乘数的个/十/百...位 * 个/十/百...位 + 进位的数值
                curr.push_back(product % 10);//取出每次计算的最小位尾插进curr
                add = product / 10;//获取进位数值
            }
           
            while(add != 0)//for结束时add可能还有(1234*9,最后add = 10,还可以再尾插一个1)
            {
                curr.push_back(add % 10);
                add /= 10;//将该加的都加上
            }

            reverse(curr.begin(),curr.end());//翻转字符串(8368->8638,string只有尾插没头插)
            for (auto &c : curr)//将ans每个字符转变为对应的整数?
            {
                c += '0';
            }
            ans = addstring(ans,curr);//每轮相乘的结果传递给add函数进行结果叠加,ans是字符串
            }

        return ans;//循环结束后返回最终答案
    }

    //("0","8638")
    string addstring(string& n1,string& n2)
    {   //(i = 0,j = 3,add = 0,)
        int i = n1.size() - 1, j = n2.size() - 1, add = 0;//i和j是两个下标,add还是进位数值
        string ans;//每次相加的结果
        while(i>=0 || j>=0 || add!=0)//让能加的全加完故不用&&,两个数的每一位从右至左一次相加
        {
            int x = i >= 0 ? n1[i] - '0' : 0;//下标小于0,则没有什么可以加的了,将其赋值为0即可
            int y = j >= 0 ? n2[j] - '0' : 0;//下标大于等于0,则获取下标对应的数值
            int result = x + y + add;//每位相加的同时将之前进位的数值也加上
            ans.push_back(result % 10);//取结果的最小位尾插进ans,该位会被视为字符插入
            add = result / 10;//获取进位数值
            i--;//向前比较
            j--;
        }
        reverse(ans.begin(),ans.end());//翻转字符串
        for (auto &c : ans)//隐式转换,看下面的题解
        {
            c += '0';
        }
        return ans;
    }
};

题解: 

  • i初始值为n,每轮i--,但每轮j=n,且j>i,故每轮j循环多一次,被乘数的个/十百位逐渐变为0
  • reverse是翻转字符串,reserve是开辟空间,前者要<algorithm>,后者要<string>
  • push_back(2)在ans中存放的是ASCII码值为2的特殊字符而不是ASCII码值为50的'2',2 +'48' = 2 + 48 = 50 = '2' 

解法二: 

class Solution {
public://num1乘数,num2是被乘数
    string multiply(string num1, string num2) {
        if (num1 == "0" || num2 == "0") 
        {
            return "0";
        }
        int m = num1.size(), n = num2.size();//m和n分别表示num1和num2的大小
        auto ansArr = vector<int>(m + n);//num1和num2相乘最大的空间是m+n

        for (int i = m - 1; i >= 0; i--)//i和j分别表示乘数和被乘数的下标,从右至左逐位遍历
        {
            int x = num1[i] - '0';//字符转整数
            for (int j = n - 1; j >= 0; j--) 
            {
                int y = num2[j] - '0';
                ansArr[i + j + 1] += x * y;//叠加
            }
        }

        for (int i = m + n - 1; i > 0; i--)//提取进位
        {
            ansArr[i - 1] += ansArr[i] / 10;//将当前坐标中的数的十位进位加到下一个坐标的存储的数值中
            ansArr[i] %= 10;//当前坐标存储只存储个位数
        }

        int index = ansArr[0] == 0 ? 1 : 0;//最高位是否为0,如果是则拷贝的下标从1开始,如果不是则从0开始

        string ans;//返回结果
        while (index < m + n) 
        {
            ans.push_back(ansArr[index]);//向ans中尾插
            index++;
        }

        for (auto &c: ans)//方法一同理
        {
            c += '0';
        }
        return ans;
    }
};

3、反转字符串中的单词 III

解法一: 

class Solution {
public:
    string reverseWords(string s) {
        string ret;
        int size = s.size();
        int i = 0;
        
        while (i < size) {
            int start = i;//子串的首下标start
            
            // 寻找第一个空格
            while (i < size && s[i] != ' ')
            {
                i++;
            }//i的下标是空格的下标而不是空格前一个字符的下标

            // 将找到的单词逆序加入结果字符串
            for (int pos = i - 1; pos >= start; --pos)//空格前一个字符的下标是子串的尾下标pos
            {
                ret.push_back(s[pos]);
            }

			//在子串间插入空格,最后一个子串不进行尾插
			if(i < size)
            {
				ret.push_back(' ');
			}
			i++; // 跳过当前的空格字符
        }
        return ret;
    }
};

解法二:


class Solution {
public:
    string reverseWords(string s) {
        int start = 0;
        for(int i = 0;i<s.size();i++)//i用来遍历整个数组下标
        {
            if(s[i+1]==' ' || i+1 == s.size())//即将到达空格或者边界
            {
                reverse(s.begin() + start,s.begin() + i + 1);//reverse的翻转范围是左闭右开的,空格刚好不会被翻转
                start = i + 2;//令start跳过空格
            }
        }
        return s;
    }
};

4、反转字符串 II

class Solution {
public:
    string reverseStr(string s, int k) 
    {
        for (int i = 0; i < s.size(); i += (2 * k))//每2*k个字符为一段待翻转字符
        {
            if (i + k <= s.size())//i+k只要不小于size就证明还能再翻转k个,就将k个字符进行翻转
            {
                reverse(s.begin() + i, s.begin() + i + k);
                continue;
            }
            //不能翻转k个就将剩余的全部翻转
            reverse(s.begin() + i, s.begin() + s.size());//翻转[i,size)范围内的字符
        }
        return s;
    }
};
  • 题目很唬人,但是将条件整合即可 

5、字符串相加

class Solution {
public:
    string addStrings(string num1, string num2) {
        string ans = "";
        int i = num1.size() - 1,j = num2.size() - 1,add = 0;//i和j分别表示num1和num2的下标,add存放进位值
        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(result % 10 + '0');//直接在插入时解决之前要用for来解决的+='0'问题
            add = result / 10;//简简单单
            --i;
            --j;
        }
        reverse(ans.begin(),ans.end());
        return ans;
    }
};
  • 跟字符串相乘处对字符的加操作一致,同时将最后for处理的内容直接在push_back处理了 

6、验证回文串

解法一: 

class Solution {
public:
    bool isPalindrome(string s) {
        string sgood;
        for (auto ch: s)//逐个读取字符串字符
        {
            if (isalnum(ch))//判断是否是字母或数字,是就插入sgood,不是就跳过,这样就不用管空格了
            {
                sgood += tolower(ch);
            }
        }
        string sgood_rev(sgood.rbegin(), sgood.rend());//翻转sgood的时将翻转结果存入sgood_rev
        return sgood == sgood_rev;//返回判断新旧字符串是否相等的结果
    }
};
  • isalnum()函数用于检查一个字符是否是字母或数字
  • tolower()函数检查
  • 对string类类型字符串的+=说函数重载后的结果,表示尾插
  • 利用范围for和auto关键字可以很好的遍历string类类型的字符串

解法二:

class Solution {
public:
    bool isPalindrome(string s) {
        string sgood;
        for (char ch: s) 
        {
            if (isalnum(ch)) 
            {
                sgood += tolower(ch);
            }
        }
        int n = sgood.size();
        int left = 0, right = n - 1;
        while (left < right) 
        {
           if (sgood[left] != sgood[right]) 
            {
                return false;
            }
            ++left;
            --right;
        }
        return true;
    }
};
  • 双指针?easy,拿下

解法三:

class Solution {
public:
    bool isPalindrome(string s) 
    {//回文串左右两端的字母应该是对称的
        int n = s.size();
        int left = 0, right = n - 1;
        while (left < right) 
        {
            while (left < right && !isalnum(s[left]))//跳过非数字和字母,如果s[left]处是数字和字母则!isalnum结果为假,否则为真
            {//当返回结果为真(s[left]处不是字母和数字就令left向右走到一个s[left]处是字母和数字的位置)
                ++left;
            }//防止比较过程中出现的空字符打乱比较对象,只能让字母和数字参与比较
            while (left < right && !isalnum(s[right]))//同理
            {
                --right;
            }

            if (left < right)//如果此时两指针仍未相遇
            {
                if (tolower(s[left]) != tolower(s[right]))//判断双方此时所指向的字母(已转换为小写)是否相同
                {
                    return false;//只要有一个不同就返回false
                }
                ++left;//如果相同就令两指针继续向中间靠拢
                --right;
            }
        }
        return true;/循环结束则返回true
    }
};
  • 遇到空格就继续向前走,因为空格不是参与比较的对象 

7、字符串最后一个单词的长度

抽象题解: 

#include<iostream>
using namespace std;

int main() {
    string s;
    while(cin >> s);
    cout << s.size();
    return 0;
}

C++题解:

#include <iostream>
#include<string>
#include <algorithm>
using namespace std;

int main()
{
    string a;
    getline(cin, a);
    int size = a.size(),count = 0;
    reverse(a.begin(),a.end());
    while(a[count]!=' ' && count < size)//注意考虑整个字符串就是一个单词的情况
    {
        count++;
    }
    cout<<count;
}

  •  getline() 函数是用于从输入流中读取一行文本的函数

8、字符串中的第一个唯一字符

class Solution {
public:
    int firstUniqChar(string s) {
        for(int i = 0; i < s.size() ; i++){
            if(s.find(s[i]) == s.rfind(s[i])){
                return i;
            }
        }
        return -1;
    }
};

  • find从左向右找子串第一次出现的位置,rfind从右向左找子串第一次出现的位置
  • find_first_of正向查找在原字符串中第一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置
  • find_last_of逆向查找在原字符串中最后一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置,逆向查找因为有'\0'所以最后一个有效字符的索引为1,'\0'为0

  • string str=“abcdefab”;
  • cout<<str.find_last_of(“wab”,5)<<endl;//从原串中下标为5开始逆向查找,首先f与待查子串每一字符比较,若有相同的就输出该字符在原串的下标。若一个都没有,就依次逆向比较,即e再与待查子串一一比较,直到原串的b与待查子串中的b相同,然后输出该b在原串的下标1

9、仅仅反转字母

解法一: 

class Solution {
public:
    string reverseOnlyLetters(string s) {
        int n = s.size();
        int left = 0, right = n - 1;
        while (true) {
            while (left < right && !isalpha(s[left])) 
            { // 判断左边是否扫描到字母
                left++;
            }
            while (right > left && !isalpha(s[right])) 
            { // 判断右边是否扫描到字母
                right--;
            }
            if (left >= right)//双指针相遇或相遇后错开就终止循环
            {
                break;
            }
            swap(s[left], s[right]);//交换此时两个指针所指向的字母
            left++;
            right--;
        }
        return s;
    }
};

  • isalpha()C++标准库函数,用于检查字符是否为字母字符,包含在<cctype>头文件 

解法二:

class Solution {
public:
    string reverseOnlyLetters(string S) {
        int begin = 0,end=S.length()-1;
        while(begin<end)
        {
            if(!isalpha(S[begin]))
                begin++;
            if(!isalpha(S[end])) 
                end--;
            if(isalpha(S[begin])&&isalpha(S[end]))
                swap(S[begin++],S[end--]);
        }
        return S; 
    }
};

~over~

  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值