力扣100

两数之和 E

双重循环

查找表(与顺序无关,用哈希表)

  • 哈希表
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        map<int,int> a;
        vector<int> b(2,-1);
        for(int i=0;i<nums.size();i++){
            if(a.count(target-nums[i])>0){
                b[0]=a[target-nums[i]];
                b[1]=i;
                break;
            }
            else a[nums[i]]=i;
        }
        return b;
    };
};
  • 二叉排序树

两数相加 M

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode *head=nullptr,*tail=nullptr;   //新节点指针
        int carry=0;                            //保存进位
        while(l1||l2){                          //l1与l2均未遍历完
            int n1=l1?l1->val:0;                //若仍有则取指,无则取0
            int n2=l2?l2->val:0;
            int sum=n1+n2+carry;
            if(!head){                          //新建头结点
                head=tail=new ListNode(sum%10);
            }else{
                tail->next=new ListNode(sum%10);//新建下一节点
                tail = tail->next;              //尾指针后移
            }
            carry=sum/10;
            if(l1){                             //若l1 l2仍存在,指针后移
                l1=l1->next;
            }
            if(l2){
                l2=l2->next;
            }
        }
        if(carry>0){                            //最高位有进位,新建节点保存
            tail->next=new ListNode(carry);
        }
        return head;
    }
};
  • 时间复杂度 O(n)
  • 空间复杂度 O(1)

无重复字符的最长子串 M

暴力解

  • 时间复杂度 O(n³)
    • 找到所有子串 双重循环,一层定头一层定尾 O(n²)
    • 判断是否无重复:Hash Set O(n)
  • 空间复杂度 O(m) m为哈希中可能出现的字符数

滑动窗口

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_set<char> occ;
        int n = s.size();
        int left=0,ans=0;
        for(int right=0;right<n;right++){
            //判断下一字符是否在子串中存在,若无则应在哈希表尾
            while(occ.find(s[right])!=occ.end()){
                occ.erase(s[left]);         //子串左侧擦除一位
                left++;                     //左指针向右移动一位
            }
            ans = max(ans,right-left+1);    //取较长子串值
            occ.insert(s[right]);           //将下一字符插入子串尾
        }
        return ans;
    }
};
  • 时间复杂度 O(n)
  • 空间复杂度 O(m) m为哈希中可能出现的字符数

寻找两个正序数组的中位数 H

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        if(nums1.size()>nums2.size()){                  //将短数组作为第一个参数
            return findMedianSortedArrays(nums2,nums1);
        }

        int m=nums1.size();
        int n=nums2.size();
        int left=0,right=m;             //短数组的左右侧
        int medianLeft=0,medianRight=0; //分界线左右的最值

        while(left<=right){
            int i=(left+right)/2;   //短数组的中位数
            int j=(m+n+1)/2-i;      //长数组的中位数

            int nums_iml = (i==0?INT_MIN:nums1[i-1]);   //短数组分界线左侧数字
            int nums_imr = (i==m?INT_MAX:nums1[i]);     //短数组分界线右侧数字
            int nums_jml = (j==0?INT_MIN:nums2[j-1]);   //长数组分界线左侧数字
            int nums_jmr = (j==n?INT_MAX:nums2[j]);     //长数组分界线右侧数字

            if(nums_iml <= nums_jmr){                   //nums_iml <= nums_jmr,则表示短左侧大于长右侧,短数组分界线应右移,反之亦然
                medianLeft = max(nums_iml,nums_jml);
                medianRight = min(nums_imr,nums_jmr);
                left = i+1;     //分界线右移
            }else{          
                right = i-1;    //分界线左移
            }
        }

        return (m+n)%2==0?(medianLeft+medianRight)/2.0:medianLeft;  //判断总数组奇偶,对应计算中位数
    }
};


  • 时间复杂度 O(logmin(m,n)))
  • 空间复杂度 O(1)

最长回文子串 M

动态规划

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        vector<vector<int>> dp(n,vector<int>(n));
        string ans;
        for(int step = 0; step<n; step++){      //step为步长,i为起点,j为终点
            for(int i = 0; i+step<n; i++){
                int j = i + step;               //起点+步长=终点
                if(step==0){                    //步长为0时,子串长度为1,均为回文
                    dp[i][j] = 1;
                }else if(step==1){
                    dp[i][j] = (s[i]==s[j]);    //步长为1时,子串长度为2,判断
                }else{
                    dp[i][j] = (s[i]==s[j] && dp[i+1][j-1]);
                }
                if(dp[i][j] && step+1>ans.size()){  //子串长度为步长+1.判断是否为最长串
                    ans = s.substr(i,step+1);
                }
            }
        }
        return ans;
    }
};
  • 时间复杂度 O(n²)
  • 空间复杂度 O(n²)

中心扩展

思路:枚举所有的「回文中心」并尝试「扩展」,直到无法扩展为止,此时的回文串长度即为此「回文中心」下的最长回文串长度。对所有的长度求出最大值,即可得到最终的答案。

class Solution {
public:
    pair<int,int> expandAroundCenter(const string& s,int left,int right){ //单次扩展函数
        while(left >=0 && right < s.size() && s[left] == s[right]){
            --left;
            ++right;
        }
        return {left+1,right-1};	//返回值为上一个子串
    }
    string longestPalindrome(string s) {
       int start = 0,end = 0;
       for(int i = 0;i < s.size(); i++){
           auto [left1,right1] = expandAroundCenter(s,i,i);     //边界1:步长为0
           auto [left2,right2] = expandAroundCenter(s,i,i+1);   //边界2:步长为1
           if(right1 - left1 > end - start){
               start = left1;
               end = right1;
           }
           if(right2 - left2 > end - start){
               start = left2;
               end = right2;
           }
       }
       return s.substr(start,end-start+1);
    }
};
  • 时间复杂度 O(n²)
  • 空间复杂度 O(1)

Manacher 算法

在每个字符间插入“#”,转化为长度2n+1的奇数子串
利用已经计算的值(法一)以及回文的对称性加速中心扩展(法二)

  • 时间复杂度 O(n)
  • 空间复杂度 O(n)

*正则式匹配 H

动态规划

视频图解参考
字符比较状态转移方程

  • 【*】:
    1. 回溯两列(前一字符不出现的情况),若为T则T,若为F转2
    2. 看正在比较的字符与【*】前字符是否相同,若相同则T,否则转3
    3. 回溯上一行同一列(前一字符出现过的情况),若相同则T,否则F
  • 【字符相同】或者【.】:
    1. copy左对角(前字符串相同,则新加相同字符串仍相同)
  • 【字符不同】F

盛水最多的容器 M

双指针

模式识别:需要移动左右两头
可以逐渐减小问题规模,排除不必要的计算,加速求解

三数之和 M

双指针

模式识别:利用排序避免重复答案
分治,降为twoSum问题
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值