题目大解析(3)

在这里插入图片描述
在这里插入图片描述


前言
这里的题目大多是用c++写的。


仅仅反转字母

原题链接仅仅反转字母
my version:

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

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

原题链接字符串中的第一个唯一字符
计数法

class Solution {
public:
    int firstUniqChar(string s) {
        int arr[130] = {0};
        for(auto x : s)
        {
            arr[x-'0']++;
        }
        int i = 0;
        for(auto x : s)
        {
            if(arr[x-'0'] == 1)
            return i;
            i++;
        }
        return -1;
        
    }
};

翻转字符串

原题链接 翻转字符串
版本一:

class Solution {
public:
    void reverseString(vector<char>& s) {
          int left = 0,right = s.size() -1;
          while(left<right)
          {
             char tmp = s[left];
             s[left] = s[right];
             s[right] = tmp;
             // swap(s[left],s[right]);这边交换可以直接用c++给的swap

             left++;
             right--;
          }
    }
};

这里不能用指针
版本二

class Solution {
public:
    void reverseString(vector<char>& s) {
         reverse(s.begin(),s.end());
    }
};

验证回文串

原题链接验证回文串
自己做的

class Solution {
public:
    bool isPalindrome(string s) {
         string s1(s.size(),'\0');
       
        string::iterator it = s.begin();
        int i = 0;
        while (it != s.end())
        {
            if (isalnum(*it))
            {
                s1[i++] = *it;
            }
            it++;
        }
        transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
        int sz = 0;
        while (s1[sz] != '\0')
        {
            sz++;
        }
        string s2(s1,0,sz);
        s1 = s2;
        reverse(s2.begin(), s2.end());
        if (s1.compare(s2) == 0)
            return true;
        else
            return false;
    }
    
};

做这道题,让我深刻意识到以下几点:

  • string类的字符串,如果要判断是否相同,它们的’\0’也要算进去
  • string类的字符串,它们的size(),length()包括’\0’

在这里插入图片描述
那么如果有’\0’存在,我们该怎么求有效字符的长度呢?
我们可以用到string类的一个函数:c_str()

void Test2()
{
    string s(10,'\0');
    //s.reserve(10);
    s[0] = 'a';
    int lenth = strlen(s.c_str());//

    cout << s << endl;
    cout << s.size() << endl;
    cout << lenth << endl;
    //cout << s.capacity() << endl;
    //s.reserve(200);
    //cout << s.capacity() << endl;

}

在这里插入图片描述

官方版本
🚗方法一:筛选 + 判断

class Solution {
public:
    bool isPalindrome(string s) {
        string sgood;
        for (char ch: s) {
            if (isalnum(ch)) {
                sgood += tolower(ch);//可以用运算符重载+=
            }
        }
        string sgood_rev(sgood.rbegin(), sgood.rend());//直接用rbegin反转
        return sgood == sgood_rev;//运算符重载==判断是否相等
    }
};

🚗方法二:双指针

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;
    }
};

🚗方法三:在原字符串上直接判断
我们直接在原字符串 sss 上使用双指针。在移动任意一个指针时,需要不断地向另一指针的方向移动,直到遇到一个字母或数字字符,或者两指针重合为止。也就是说,我们每次将指针移到下一个字母字符或数字字符,再判断这两个指针指向的字符是否相同

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])) {
                ++left;
            }
            while (left < right && !isalnum(s[right])) {
                --right;
            }
            if (left < right) {
                if (tolower(s[left]) != tolower(s[right])) {
                    return false;
                }
                ++left;
                --right;
            }
        }
        return true;
    }
};

把字符串转换成整数

原题链接把字符串转换成整数

my version:

class Solution {
public:
    bool IsLegal(string str)
    {
        for(auto ch : str)
        {
            if((ch>'9'||ch<'0'))
            return false;
        }
        return true;
    }
    int StrToInt(string str) {
        if(str.size() == 0)
        return 0;
         if(((str[0]!='+'&&str[0]!='-')&&(str[0]>'9'||str[0]<'0')))
        return 0;
        string s1(str,1);
       
        if(IsLegal(s1) == false )
        return 0;
        int lenth = str.size();
        if(str[0]=='+'||str[0]=='-')
        lenth--;
        int sum = 0;
        string s2 = (str[0]<='9'&&str[0]>='0') ? str:s1;
        for(auto ch : s2)
        {
            int x = ch - '0';
            sum+=x*pow(10,lenth - 1);
            lenth--;
        }
        if(str[0]=='-')
        sum = -sum;
         return sum;
    }
};

other version:

class Solution {
public:
    int StrToInt(string str) {
        int ans = 0;int isplus = 1;
        for(char ch:str){
            if(isalpha(ch))
            {
                return 0;
            }if (ch == '+' || ch =='-')
            {
                isplus = (ch == '+') ? 1 : -1;
            }
            if(isdigit(ch))
            {
                ans = ans*10+ch-'0';
            }
        }return isplus*ans;
    }
};

这个版本厉害!

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

原题链接字符串最后一个单词的长度

my version:

#include <iostream>
using namespace std;

int main() {
     string s;
     getline(cin,s);//这样可以输入空格
     int len;
    if(s.rfind(' ')==string::npos)
       len = s.size();
    else
       len = s.size()-s.rfind(' ') - 1;
       cout<<len;
}

字符串相加

原题链接 字符串相加

my version:

class Solution {
public:
    string addStrings(string num1, string num2) {
        //假设num1的长度最小
        string s;
       
        if(num1.size()>num2.size())
         {
             swap(num1,num2);//交换一下
         }
          
        int end1 = num1.size() - 1,end2 = num2.size() - 1;//end1<=end2
        int tmp = 0,next = 0;
        char ch;
        while(end2>=0)
        {
            if(end1>=0)
            {
                 tmp = num1[end1]-'0'+num2[end2] - '0'+next;
                 next = 0;
                 if(tmp>9)
                 next = 1;
                 tmp%=10;
                 ch = tmp+'0';
                 s+=ch;
            }
            else
            {
                tmp = num2[end2] - '0' + next   ;
                next = 0;
                if(tmp>9)
                next = 1;
                tmp%=10;
                 ch = tmp+'0';
                 s+=ch;
            }
            end1--;
            end2--;
            if(end2==-1&&next==1)
            {
                s+='1';
            }
        }
         reverse(s.begin(),s.end());
         return s;
    }
};

优化一下:

class Solution {
public:
    string addStrings(string num1, string num2) {
        //假设num1的长度最小
        string s;
       
        if(num1.size()>num2.size())
         {
             swap(num1,num2);//交换一下
         }
          
        int end1 = num1.size() - 1,end2 = num2.size() - 1;//end1<=end2
        int tmp = 0,next = 0;
        int _num1;
        char ch;
        while(end2>=0)
        {
            if(end1>=0)
             _num1 = num1[end1]-'0';
            else
            _num1 = 0;

            tmp = _num1+num2[end2] - '0'+next;
                 next = 0;
                 if(tmp>9)
                 next = 1;
                 tmp%=10;
                 ch = tmp+'0';
                 s+=ch;
            end1--;
            end2--;
            if(end2==-1&&next==1)
            {
                s+='1';
            }
        }
         reverse(s.begin(),s.end());
         return s;
    }
};

其实这里while的判断条件改为二者都>=0就行了。
这样就不用可以去比较num1和num2的长度

反转字符串 II

原题链接 反转字符串 II

my version:

class Solution {
public:
    string reverseStr(string s, int k) {
        int left = 0, right = k - 1;
        int count = 0;
        for (int i = 0;i<s.size(); i++)
        {
            count++;
            if (count == 2 * k)
            {
                int tmp1 = left,tmp2 = right;
                while (tmp1 < tmp2)
                {
                    swap(s[tmp1++], s[tmp2--]);
                }
                left+=2*k;
                right = left + k - 1;

                count = 0;
            }
            int len = s.size() - left;
            if (len < k)
            {
                right = s.size() - 1;
                while (left < right)
                {
                    swap(s[left], s[right]);
                    left++;
                    right--;
                }
                break;
            }
            if(len<2*k&&len>=k)
            {
                 while (left < right)
                {
                    swap(s[left], s[right]);
                    left++;
                    right--;
                }
                break;
            }
            
        }
        return s;
    }
};

official version:

class Solution {
public:
    string reverseStr(string s, int k) {
        int n = s.length();
        for (int i = 0; i < n; i += 2 * k) {
            reverse(s.begin() + i, s.begin() + min(i + k, n));
        }
        return s;
    }
};

看完后感觉自己的作法简直是猿古人😅

反转字符串中的单词 III

原题链接反转字符串中的单词 III

my version:

lass Solution {
public:
    string reverseWords(string s) {
      size_t begin = 0,end = s.find(' ');
      while(string::npos!=end)
      {
          reverse(s.begin()+begin,s.begin()+end);
          begin = end+1;
          end = s.find(' ',end+1);
      }
          reverse(s.begin()+begin,s.end());

      return s;
    }
};

字符串相乘

原题链接字符串相乘
my version:

class Add {
public:
    string addStrings(string num1, string num2) {
        //假设num1的长度最小
        string s;

        if (num1.size() > num2.size())
        {
            swap(num1, num2);//交换一下
        }

        int end1 = num1.size() - 1, end2 = num2.size() - 1;//end1<=end2
        int tmp = 0, next = 0;
        int _num1;
        char ch;
        while (end2 >= 0)
        {
            if (end1 >= 0)
                _num1 = num1[end1] - '0';
            else
                _num1 = 0;

            tmp = _num1 + num2[end2] - '0' + next;
            next = 0;
            if (tmp > 9)
                next = 1;
            tmp %= 10;
            ch = tmp + '0';
            s += ch;
            end1--;
            end2--;
            if (end2 == -1 && next == 1)
            {
                s += '1';
            }
        }
        reverse(s.begin(), s.end());
        return s;
    }
};

class Solution {
public:
    string multiply(string num1, string num2) {
        int end1 = num1.size() - 1, end2 = num2.size() - 1;
       
        string sum("");
        Add add;
        for (int i = end1,mu = 0; i >= 0; i--,mu++)
        {
            string s("");
            int next = 0;
            for (int j = end2; j >= 0; j--)
            {
                int x1 = num1[i] - '0';
                int x2 = num2[j] - '0';


                int ref = ((x1 * x2) + next)%10;//要插入stirng的数字
                next = ((x1 * x2) + next) / 10;//下回合要加的

                s += ref + '0';
            }

            if (next != 0)
                s += next + '0';
            reverse(s.begin(), s.end());
            //接下来要追加0
            for (int k = 0;k < mu; k++)
            {
                s += '0';
            }
            sum = add.addStrings(sum, s);
        }
        if(sum[0]=='0')
        sum = '0';
        return sum;
    }
};

只出现一次的数字

原题链接只出现一次的数字
异或作法:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
          int val = 0;
          for(auto x:nums)
          {
              val^=x;

          }
          return val;
          
    }
};

杨辉三角

原题链接杨辉三角

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> vv;
        //首先我们先开辟需要的二维数组空间
        vv.resize(numRows);//用resize主要是为了初始化为0
        int i = 0;
        for(i = 0;i<numRows;i++)
        {
            vv[i].resize(i+1);
            vv[i][0] = vv[i][vv[i].size()-1] = 1;//每一行的首尾初始化为1
        }
        //开始将其余赋值
        for(i = 0; i<numRows;i++)
        {
            for(int j = 0;j<vv[i].size();j++)
            {
                if(vv[i][j]==0)
                {
                    vv[i][j] = vv[i-1][j]+vv[i-1][j-1];
                }
            }
        }
        return vv;
    }
};

在这里插入图片描述

删除有序数组中的重复项

原题链接删除有序数组中的重复项
思路;
在这里插入图片描述
MyCode;

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
         int tmp = nums[0],count = 0, k = 0;
         for(int i = 1 ;i<nums.size();)
         {
                if(nums[i]==tmp)
                {
                    count++;
                    nums.erase(nums.begin()+i);//删后不能再++
                }
                else
                {
                   tmp = nums[i];
                    count = 0;
                }
                if(count == 0)
                {
                    k++;
                    i++;
                }
         }
         return nums.size();
    }
};

这道题我感觉题目表述不是很好,返回唯一元素的个数,我以为是原数组中唯一元素的个数,
但实际,就是返回删完后的数组的长度(因为此时重复项都删完肯定都唯一了🤣)

只出现一次的数字 II

原题链接
只出现一次的数字 II
法一:依次确定每一个二进制位
在这里插入图片描述

class Solution {
public:

    int singleNumber(vector<int>& nums)
     {
         int ans = 0;
         for(int i = 0;i<32;i++)
         {
             int sum = 0;
             for(int e:nums)//遍历每一位二进制位,&1后将该位所有的0/1情况相加
             {
                 sum+=((e>>i)&1);
             }
             if(sum%3)//要么sum%3==1,要么==0,如果不等于0,说明该位应该是1
             {
                 ans|=(1<<i);
             }
         }
         return ans;
    }
  
};

二叉树的层序遍历

原题链接二叉树的层序遍历

队列法

Code:

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> q;//创建一个队列存入每一层的节点
        int levelsize = 0;
        if(root)//如果不为空
        {
            q.push(root);
            levelsize++;
        }
        vector<vector<int>> vv;
         while(!q.empty())
         {
             vector<int> v;
             while(levelsize--)
             {
                 TreeNode* front = q.front();
                 q.pop();//出队列
                 //接下来开始入下一个头节点的数据
                if(front->left)
                q.push(front->left);
                if(front->right)
                q.push(front->right);
                 v.push_back(front->val);
             }
            vv.push_back(v);
             levelsize = q.size();
             
         }
         return vv;

    }
};

思路
我们创建一个队列,这个队列的作用是什么呢?
这个队列的作用主要就是先存入二叉树的一层数据,然后又负责将刚刚存入那一层的数据给出队列,然后再入下一层的队列,直到队列为空。
这中间的具体细节是什么呢?
在这里插入图片描述
当我们在出一个层的数据时,我们怎么知道该层到底有多少个数据呢?
实际上,在我们出某一层的数据同时,我们也在入下一层的数据,当该层的数据出完后,下一层的数据也入完了

如上图中,
入第一层:1先入进去
出第一层和入第二层:此时1指向了2和3,当1出完后,2和3随后入队列,刚刚好第二层入完了。
出第二层和入第三层:
1.先出2,此时2指向了4和空, 4再入队列,此时队列中的数据为3 4
2.再出3,3指向了5和6,5和6再入队列,此时第二层出完了,正好第三层也入完了。

所以我们总结一下,这就是一个出n层入n+1层的循环,循环次数为n层中的数据个数

逆波兰表达式求值

原题链接:逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/)

Code:

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> s;

        for(int i = 0;i<tokens.size();i++)
        {
            //如果为数字,就先入栈等待遇到运算符计算
            string& str = tokens[i];
            if(!("+" == str || "-" == str || "*" == str || "/" == str))
            {
                s.push(atoi(str.c_str()));
            }
            else//此时就要开始计算了
            {
                int right = s.top();
                s.pop();
                int left = s.top();
                s.pop();
                switch(str[0]){

              
                case '+':
                s.push(left+right);
                 break;
                case '-':
                s.push(left-right);
                 break;
                case '*':
                s.push(left*right);
                 break;
                case '/':
               s.push(left/right);
                 break;
                 default:
                 break;
                } 
            }
        }
         return s.top();
 }
};

中缀表达式->后缀表达式思路
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值