LeetCode记录(Cpp)

【持续更新中】
一些小细节or遗忘点or疑问的汇总
写写题让自己习惯写c++而不是以前那种按c的写法写c++
而且leetcode不用自己处理输入输出也不用本地运行意外的很爽(懒死我算了XD

记忆点汇总

指针

string

str.substr(st,len); 生成从st开始长度为len的s的子字符串

isspace(c)
isdigit(c)

STL

vector

动态数组

v.empty() v为空返回true,否则返回false
v.size() 返回v中元素个数
v.push_back(t) 向v的末尾添加一个值为t的元素
v.pop_back() 删除v末尾的元素,如果v为空,行为未定义
v[n] 返回v中第n个位置上的元素的引用,位置n从0开始计
v.clear 清空向量中的元素
v1 = v2 赋值
v = {a,b,c,...} 替换
v1 == v2 v1 != v2 v1和v2相等当且仅当他们的元素数目相同且对应位置元素相同
<,<=,>,>= 以字典顺序进行比较
v.at(n) (cin>>v.at(0);) 返回v中第n个位置上的元素的引用,下标越界抛出异常

迭代器

vector<int>::iterator it;
for(it=a.begin();it!=a.end();it++)
    cout<<*it<<" ";

其他

a.insert(a.begin(), 10) ;                      //将10插入到向量a的起始位置前
a.insert(a.begin(), 3, 10);                   //将10分别插入到向量a的0-2处
b.insert(b.begin(), a.begin(), a.end()); //将a插入到b.begin前
a.erase(a.begin());                             //将起始位置的元素删除
a.erase(a.begin(), a.begin() + 3);        //将a的0-3处元素删除
a.swap(b);                                         //将向量a与向量b交换

map

map与unordered_map区别及使用

map - 红黑树
unordered_map - 哈希表

题目记录

1. Two Sum

数组中找两个数使其和为target的值。本来的思路是排序后从前后往中间找,结果发现排序后下标就变了没法返回正确的下标(如果是自己处理输入的话会考虑用结构体标记数的初始位置),所以索性就暴力了(反正没超时就行XD

//#include<algorithm>
using std::cout;

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
      /* 排序后从两边到中间遍历的代码 
      	std::sort(nums.begin(),nums.end());
        int i=0,j=nums.size()-1;   
        while(i<j){
            if(nums[i]+nums[j]==target)break;
            if(nums[i]+nums[j]>target){cout<<0;
                j--;
            }
            else i++;
        }
        vector<int> ans;
        ans.push_back(i);
        ans.push_back(j);
        return ans;*/
        int i,j,flag=0;
        vector<int> ans;
        for(i=0;i<nums.size();i++){
            for(j=i+1;j<nums.size();j++){
                if(nums[i]+nums[j]==target){
                    flag=1;break;
                }
            }if(flag==1)break;
        }
        ans.push_back(i);
        ans.push_back(j);
        return ans;
    }
};

提一嘴备注掉的代码,省得以后忘了,可以理解成在坐标轴给定点中找 两点构成的线段中点的值*2==target 的线段 ,所以寻找过程中当值比目标值大or小的时候只要往中间移动其中一端就可以了

2. Add Two Numbers

链表加法,和以前写过的一题不同的是这次用链表表示的数是 个位->十位->百位 这样加法进位处理起来就很轻松。我这里直接把加完的结果更新到第一个链表中,没有开新的
指针练的少,写的时候老容易分不清然后出语法错误…
出现的问题:更高位接上去出现数组越界,还是看到题解里Java代码用new才想起来cpp也有这个东西XD

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        int an=0,m=0;
        ListNode *a=l1,*b=l2;
        while(1){
            an=a->val+b->val+m;
            m=an/10;
            an=an%10;
            a->val=an;
            
            if(a->next!=NULL && b->next!=NULL){
                a=a->next;b=b->next;
            }
            else break;
        }
        if(b->next!=NULL){     
            a->next=b->next;
        }
        while(m!=0){
            if(a->next!=NULL){
                a=a->next; 
                an=a->val+m;
                m=an/10;
                an=an%10;
                a->val=an;
            }
            else{
               // ListNode aa(m%10);直接赋值会越界
                a->next=new ListNode(m%10); //new一个新的
                a=a->next;
                m=m/10;
            }
        }
        return l1;
    }
};

3. Longest Substring Without Repeating Characters

字符串中最长无重复字符子串
我用的方法是标记子串中出现过的字符,依次以主串中的每个字符作为子串首字符进行遍历
wa点:本题字符包括所有字母数字符号空格,即ASCII表中32~126全包括在内
疑问:memset对数组进行初始化时数组长度不用sizeof(flag)会出问题,无法全部置0,为什么?

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int flag[100],maxx=0,m=0;
        memset(flag,0,sizeof(flag));      //为什么写100没法全置零,用sizeof(flag)可以??
        for(int i=0;i<s.length();i++){   
            int j=i;
            while(s[j]>=' '){ 
                if(flag[s[j]-' ']!=0){       
                    if(m>maxx) maxx=m;
                    m=0;
                    memset(flag,0,sizeof(flag));
                    break;
                }
                else{
                    flag[s[j]-' ']=1;
                    m++;
                    j++;
                }
            }
            if(m>maxx) maxx=m;
            if(s.length()-i<maxx) break;
        }
        return maxx;
    }
};

4. Median of Two Sorted Arrays

求两个增序数组的中位数,看到hard做好了卡题准备,结果一写,就这??就这????
一发过,解法也没啥好说的…完全不能理解hard在哪…

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int n=nums1.size(),m=nums2.size();
        int flag=(m+n)/2,t=0,i=0,j=0;
        double a=0.0,b=0.0;
        while(t<=flag){
            if(i<n&&j<m){
                if(nums1[i]<nums2[j]){
                    b=nums1[i];
                    i++;
                }
                else{
                    b=nums2[j];
                    j++;
                }
            }
            else if(i<n){
                b=nums1[i];i++;
            }
            else if(j<m){
                b=nums2[j];j++;
            }
            if(t==flag-1) a=b;
            t++;
        } 
        if((m+n)%2==0) return (a+b)/2;
        else return b;
    }
};

5. Longest Palindromic Substring ★

这题就比较有意思了,求字符串最长回文子串

  1. 动规
    子串长度为1,一定是回文串;长度为2,若两个字符相等为回文串;
    对于一个长度大于2的回文子串,去掉首位字符后依旧是回文子串,即若回文串两端新增的字符相等则新的字符串依旧是回文串
  2. 中心扩散
    所有状态在转移的时候的可能性都是唯一的。即从所有边界情况(子串长度为1或2)开始扩展也能得到所有状态对应的答案
    枚举边界情况并从边界子串向两端扩展,两边字母相同继续扩展;字母不同停止扩展并进入下一种边界情况
  3. Manacher算法O(n)
    基于动规+中心扩散的优化算法,真的很巧妙
    首先在字符串中间隔插入特殊字符使所有回文串情况转化为单数形
    (插入字符后的回文子串长度-1)/2 = 原始回文子串长度 = 以 i 为中心能扩散的步数
    在这里插入图片描述
    用p[i]存储以i点为中心的最大扩散长度分四种情况:
    (1)i >= maxRight用中心扩散向两边匹配
    因为此时 i 没有被包含在以center为对称中心的回文串内,无法利用回文串的对称性
    (2)i < maxRight这里考虑以对称点mirror为中心的最长回文串的长度,包含三种情况:
    ······1. p[mirror] < maxRight - i时,p[i] = p[mirror]
    ······2. p[mirror] == maxRight - i时,p[i] >= maxRight-1 需扩散求值
    ······3. p[mirror] > maxRight - i时,p[i] = maxRight - i
    这三种情况综合可得 p[i] = min( p[mirror] , maxRight - i ),并尝试中心扩散

按Manacher写:

class Solution {
public:
    int expend(string &s, int left, int right){
        while(left>=0&&right<s.length()&&s[left]==s[right]){
            left--;right++;
        }
        return (right-left-2)/2;
    }
    
    string longestPalindrome(string s) {
        string t="#";
        for(char c:s){
            t+=c;
            t+='#';
        }
        t+='#';s=t;
        
        vector<int> p; 
        int st=0,ed=-1,cen=0,right=0;
        for(int i=0;i<s.length();i++){
            int x;
            if(i>=right){
                x=expend(s,i,i);
            }
            else{
                x=min(p[2*cen-i],right - i);
                x=expend(s,i-x,i+x);
            }
            p.push_back(x);
            if(i+x>right){
                right=i+x;
                cen=i;
            }
            if(x*2+1>ed-st){
                st=i-x;
                ed=i+x;
            }
        }
        
        t.clear();
        for(int i=st;i<=ed;i++){
            if(s[i]!='#'){
                t+=s[i];
            }
        }
        return t;
    }
};


这两次提交之间我只是把expend(string s, int left, int right)改成了引用expend(string &s, int left, int right)。好家伙,我快乐了

6. ZigZag Conversion

就,找下标规律,按行取数

class Solution {
public:
    string convert(string s, int numRows) {
        string ans;
        int len=s.length();
        int mid=numRows*2-2;
        
        if(numRows==1) return s;
       
        for(int j=0;j<numRows;j++){
            for(int i=0;i<len;i+=mid){
                if(i+j<len) ans+=s[i+j];
                                          
                if(i+mid-j<len&&j!=0&&j!=numRows-1) ans+=s[i+mid-j];                             
            }
        }
        return ans;
    }
};

7. Reverse Integer

注意判断溢出

class Solution {
public:
    int reverse(int x) {
        int a=0;
        while(x){
            int mid=x%10;
            if(a>INT_MAX/10||(a==INT_MAX/10&&mid>7)) return 0;
            if(a<INT_MIN/10||(a==INT_MIN/10&&mid<-8))return 0;
            a=a*10+mid; x=x/10;
        }
        return a;
    }
};

8. String to Integer (atoi)

最开始题目审错了wa了几次。其实就是顺序的状态转变
普通解法:

class Solution {
public:
    int myAtoi(string s) {
        int ans=0,flag=1,i=0;
        while(s[i]==' '&&i<s.length())i++;
        if(s[i]=='-'){flag=-1;i++;}
        else if(s[i]=='+'){
            i++;
        }
        while(s[i]=='0') i++;
        
        while(i<s.length()){          
            int mid=s[i]-'0';              
            if(mid<0||mid>9) break;
            if(ans==0&&s[i]=='0') {i++;continue;}
            
            mid=mid*flag;
            if(ans>INT_MAX/10||(ans==INT_MAX/10&&mid>=7)) return INT_MAX;
            if(ans<INT_MIN/10||(ans==INT_MIN/10&&mid<=-8))return INT_MIN;
            ans=ans*10+mid; 
            i++;
        }
        return ans;
    }
};

DFA(有穷自动机:

class Automaton{
    string state="st";
    unordered_map<string,vector<string>> table={
        {"st",{"st","sign","num","ed"}},
        {"sign",{"ed","ed","num","ed"}},
        {"num",{"ed","ed","num","ed"}},
        {"ed",{"ed","ed","ed","ed"}}
    };
    int flag_c(char c){
        if (isspace(c)) return 0;           //空格
        if (c=='+'||c=='-') return 1;
        if (isdigit(c)) return 2;           //数字
        return 3;
    }
public:
    int sign=1;
    long long ans=0;
    
    void get(char c){
        state = table[state][flag_c(c)];
        if(state=="sign"){
            sign=(c=='+'?1:-1);
        }
        else if(state=="num"){
            ans=ans*10+(c-'0');
            ans=(sign==1?min(ans,(long long)INT_MAX):min(ans,-(long long)INT_MIN));
        }
    }
};

class Solution {
public:
    int myAtoi(string s) {
        Automaton autom;
        for(char c:s){
            autom.get(c);
        }
        return autom.ans*autom.sign;
    }
};

在这里插入图片描述
单就这题而言自动机似乎没普通解法优

9. Palindrome Number

class Solution {
public:
    bool isPalindrome(int x) {
        if(x<0) return false;
        long long bef=x,aft=0;
        while(x){
            aft=aft*10+x%10;
            x=x/10;
        }
        if(bef==aft)return true;
        else return false;
    }
};
//从结果上来看下面这个优化了时间
class Solution {
public:
    bool isPalindrome(int x) {
        if(x<0||x%10==0&&x!=0) return false;
        if(x>=0&&x<10) return true;
        int aft=0;
        bool flag;
        while(x){
            aft=aft*10+x%10;
            x=x/10;               
            if(aft>=x){
                if(aft==x) flag=true;
                else if(aft>=10&&aft/10==x) flag=true;
                else flag=false;
                break;
            }
        }
        return flag;
    }
};

10. Regular Expression Matching❓

题解
动规,思路算是看懂了…但是代码里还有些疑问

class Solution {
public:
    bool isMatch(string s, string p) {
        int slen=s.length();
        int plen=p.length();
        
        auto matche = [&](int i,int j){
            if(i==0) return false;
            if(p[j-1]=='.')return true;
            return s[i-1]==p[j-1];
        };  //auto matche = [&](int a,int b){...};没懂,这算函数吗?还是定义?
        
        vector<vector<int>> f(slen+1,vector<int>(plen+1));
        f[0][0]=true;
        for(int i=0;i<=slen;i++){
            for(int j=1;j<=plen;j++){
                if(p[j-1]=='*'){
                    f[i][j]|=f[i][j-2];         //按位与?
                    if(matche(i,j-1)){
                        f[i][j]|=f[i-1][j];
                    }
                }
                else{
                    if(matche(i,j)) f[i][j]|=f[i-1][j-1];
                }
            }
        }
        return f[slen][plen];
    }
};

11. Container With Most Water

两边往中间找最优解

class Solution {
public:
    int maxArea(vector<int>& height) {
        int nowl=0,nowr=height.size()-1;
        int maxx=0;
        while(nowr>nowl){
            int nm=(nowr-nowl)*min(height[nowr],height[nowl]);
            maxx=max(maxx,nm);
            if(height[nowr]<height[nowl]){
                nowr--;
            }
            else{
                nowl++;
            }
        }
        return maxx;
    }
};

12. Integer to Roman

这个是贪心。不过直接分类比较速度和内存都更优,但代码会比较长

class Solution {
public:
    string intToRoman(int num) {
        vector<int> value={1000,900,500,400,100,90,50,40,10,9,5,4,1};
        vector<string> symbol={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        string ans;
        int i=0;
        while(num){
            while(num>=value[i]){
                ans=ans+symbol[i];
                num=num-value[i];
            }
            i++;
        }
        return ans; 
    }
};

在这里插入图片描述
直接暴力分类的:(缺点就是代码长XD
在这里插入图片描述

class Solution {
public:
    string Roman(int flag,int x){
        string s;
        if(flag==1){
            if(x==4) s="IV";
            else if(x==9) s="IX";
            else if(x>=5){ 
                s="V";
                x=x-5;
                while(x--)s=s+"I";
            }
            else{
                while(x--)s=s+"I";
            }
        }
        else if(flag==2){
            if(x==4) s="XL";
            else if(x==9) s="XC";
            else if(x>=5){ 
                s="L";
                x=x-5;
                while(x--)s=s+"X";
            }
            else{
                while(x--)s=s+"X";
            }
        }
        else if(flag==3){
            if(x==4) s="CD";
            else if(x==9) s="CM";
            else if(x>=5){ 
                s="D";
                x=x-5;
                while(x--)s=s+"C";
            }
            else{
                while(x--)s=s+"C";
            }
        }
        else if(flag==4){
            while(x--)s=s+"M";
        }
        return s;
    }
    string intToRoman(int num) {
        string ans;
        int flag=0,x;
        while(num){
            x=num%10;
            num=num/10;
            flag++;
            string st;
            st=Roman(flag,x);    
            ans=st+ans;
        }
        return ans; 
    }
};

13. Roman to Integer

小值右边有大值用减,没大值用加

class Solution {
public:
    int getValue(char c){
        int num=0;
        if(c=='M') num=1000;
        else if(c=='D') num=500;
        else if(c=='C') num=100;
        else if(c=='L') num=50;
        else if(c=='X') num=10;
        else if(c=='V') num=5;
        else if(c=='I') num=1;
        return num;
    }
    int romanToInt(string s) {
        int ans=0;
        int i=0,len=s.length();
        for(i=0;i<len;i++){
            int flag=1;
            if(getValue(s[i])<getValue(s[i+1])) flag=-1;
            ans+=flag*getValue(s[i]);
        }
        return ans; 
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值