常考算法题

二分类:有序数组翻转后找值class Solution { public: int search(int A[], int n, int target){ int begin = 0; int end = n-1; while(begin <= end){ int mid = (be...
摘要由CSDN通过智能技术生成

目录

二分

有序数组翻转后找值

动态规划

最小编辑距离

最大连续子序列和dp[i] = (dp[i-1]+a[i], a[i]);

最长上升子序列

最长公共子序列

最长公共子串

字符串匹配

最大无重复子串

最长回文子串

股票的最大价值:交易一次:1.更新最低点,2.更新利润 maxProfit = prices[i] - minPrice;

股票的最大价值2:可以交易多次。1.更新利润。maxProfit += prices[i] - prices[i-1];

排序

快排

归并排序

堆排序

二叉树序列化和反序列化

二叉搜索树于双向链表

是否存在子树

树的非递归遍历

回溯算法:

17.电话号码

39.组合总和:给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 tar

40. 组合总和 II:给定的数组中包重复元素

46. 全排列

47. 全排列 II

78. 子集

90. 子集 II给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

括号生成:递归

括号匹配:

二叉树

二叉树的最近公共祖先节点:主要的思想就是从根节点开始。

排序二叉树的最近公共祖先节点:

二叉树的最大路径

二叉树中第k小的元素

链表

排序链表:化整为零的归并

k个有序链表合并:化零为整的归并

链表加法1:直接从左往算。

链表加法2:从右往左:栈结构+链表加法1.



二分

有序数组翻转后找值

class Solution {  
public:
    int search(int A[], int n, int target){  
        int begin = 0;  
        int end = n-1;  
        while(begin <= end){  
            int mid = (begin + end)/2;  
            //判断mid是否为target,如果是,直接返回,如果不是,再判断target是在前半段还是后半段  
            if(A[mid] == target){  
                return mid;  
            }  
            //如果前半段有序  
            if(A[begin] <= A[mid]){  
                //判断target是否在前半段,如果在,则继续遍历前半段,
                //如果不在,则继续遍历无序的后半段  
                if(A[begin] <= target && target < A[mid])  
                    end = mid - 1;  
                else  
                    begin = mid + 1;  
            }  
            //如果后半段有序  
            else{  
                //判断target是否在后半段,如果在,继续遍历后半段,
                //如果不在后半段,则继续遍历无序的前半段  
                if(A[mid] < target && target <= A[end])  
                    begin = mid + 1;  
                else  
                    end = mid - 1;  
            }  
        }  
        return -1;  
    }  

}

动态规划

最小编辑距离

int minDistance(string word1, string word2) {
    int n1 = word1.size();
    int n2 = word2.size();
    vector<vector<int>> dp(n1+1,vector<int>(n2+1));
    
    //第一列
    for(int i=0;i<=n1;++i)
        dp[i][0]=i;
    //第一行
    for(int j=0;j<=n2;++j)
        dp[0][j]=j;
    
    for(int i=1;i<=n1;++i)
        for(int j=1;j<=n2;++j){
            if(word1[i-1]==word2[j-1])
                dp[i][j] = dp[i-1][j-1];
            else
                dp[i][j] = min(min(dp[i-1][j-1],dp[i][j-1]),dp[i-1][j])+1;
        }
    return dp[n1][n2];
}

最大连续子序列和dp[i] = (dp[i-1]+a[i], a[i]);

#include <iostream>
using namespace std;
int main(){
    int a[100], n;
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }

    int dp[1000];
    int maxNum = INT_MIN;
    dp[0] = 0;
    for(int i = 1; i <= n; i++){
        dp[i] = max(dp[i - 1] + a[i], a[i]);///状态转移方程,表示以第i个数结尾的连续子序列的
    最大和
        maxNum = max(maxNum, dp[i];
    }
    cout << maxNum << endl;
    return 0;
}

最长上升子序列

dp[i]保存的是以nums[i]结尾的最长子序列,不是前i个元素中的最长子序列,所以还要用一个maxLIS来记录最长的
class Solution {
  public:
    int lengthOfLIS(vector<int> &nums) {
        if (nums.size() == 0)
            return 0;
        vector<int> dp(nums.size(), 0);
        dp[0] = 1;
        int maxLIS = 1;
        for (int i = 1; i < nums.size(); i++) {
            dp[i] = 1;
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j] && dp[i] < dp[j] + 1)
                    dp[i] = dp[j] + 1;
                maxLIS = max(dp[i], maxLIS);
            }
        }
        return maxLIS;
    }
};

最长公共子序列

int longestSubsequen(string x, string y) {
    int **dp = new int*[x.size() + 1];
    for (int i = 0; i < x.size(); i++) {
        dp[i] = new int[y.size() + 1];
    }
    for (int i = 0; i <= x.size(); i++) dp[i][0] = 0;
    for (int i = 0; i <= y.size(); i++) dp[0][i] = 0;
    for (int i = 1; i <= x.size(); i++) {
        for (int j = 1; j <= y.size(); j++) {
            if (x[i] == y[j]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            }
            else {
                dp[i][j] = dp[i - 1][j] > dp[i][j - 1] ? dp[i - 1][j] : dp[i][j - 1];
            }
        }
    }
    return dp[x.size()][y.size()];
}

最长公共子串

int longestSubstring(string x, string y) {
   vector<vector<int> > f(x.size() + 1, vector<int>(y.size() + 1, 0));
   int max = -1;
   for (int i = 1; i <= x.size(); i++) {
       for (int j = 1; j <= y.size(); j++) {
           if (x[i - 1] != y[j - 1])
                 f[i][j] = 0;
           else if (x[i - 1] == y[j - 1]) 
                 f[i][j] = f[i - 1][j - 1] + 1;
           if (max < f[i][j]) {
                 max = f[i][j];
           }
       }
    }
    return max;
}

字符串匹配

class Solution {
public:
    vector<vector<int>>f;
    int n, m;
    bool isMatch(string s, string p) {
        n = s.size();
        m = p.size();
// 为什么不是n,m 因为考虑到s,p都为空的情况
        f = vector<vector<int>>(n + 1, vector<int>(m + 1, -1));
        return dp(0, 0, s, p);
    }

    bool dp(int x, int y, string &s, string &p)
    {
//利用到的f[x][y] 有值说明已经计算过,直接返回不需要再去递归。利用到已经计算到的值,截枝不让重复递归
        if (f[x][y] != -1) return f[x][y];
        if (y == m)
            return f[x][y] = x == n;
        bool first_match = x < n && (s[x] == p[y] || p[y] == '.');
        bool ans;
        if (y + 1 < m && p[y + 1] == '*')
        {
            ans = dp(x, y + 2, s, p) || first_match && dp(x + 1, y, s, p);
        }
        else
            ans = first_match && dp(x + 1, y + 1, s, p);
        return f[x][y] = ans;
    }
};

最大无重复子串

int fun(vector<int> arr){
    unordered_map<int> hash;
    for(int i = 0, j = 0; i < arr.size(); i++){
            hash[s[i]]++;
            while(hash[s[i]] > 1){
                hash[s[j++]--];
            }
            res = max(res, i-j+1);
     }
     return res;
}

最长回文子串

string ishuiwen(string s){
    string res;
    for(inti = 0; i < s.size(); i++){
        string left = helper(s, i, i+1);
        string right = helper(s, i, i);
        if(left.size() > res.size())
            res = left;
        if(right.size() > res.size())
            res = right;
        }
    return res;
}
string helper(string s, int left, int right){
    while(left >= 0 && right < s.size() && s[left] == s[right]){
        left--;
        right++;
    }
    
    return s.substr(left+1, right - left - 1);
}

股票的最大价值:交易一次:1.更新最低点,2.更新利润 maxProfit = prices[i] - minPrice;

  int maxProfit(vector<int>& prices) {
        int minPrice = INT_MAX;
        int maxProfit = 0;
        for(int i = 0; i < prices.size(); i++){
                if(prices[i] < minPrice)
                    minPrice = prices[i];
                else if(prices[i] - minPrice > maxProfit)
                        maxProfit = prices[i] - minPrice;
                
        }
        return maxProfit;
    }

股票的最大价值2:可以交易多次。1.更新利润。maxProfit += prices[i] - prices[i-1];

 int maxProfit(vector<int>& prices) {
        int sum = 0;
        for(int i = 1; i < prices.size(); i++){
           if(prices[i] > prices[i-1]){
               sum = sum + prices[i] - prices[i-1];
           }
        }
        return sum;
    }

排序

快排

#include<iostream>
using namespace std;
int getIndex(int arr[], int low, int high){
        int key = arr[low];
        while(low < high){
                while(low < high && arr[high] >= key){
                        high--;
                }
                if(low < high)
                        arr[low] = arr[high];
                while(low < high && arr[low] <= key)
                        low++;
                if(low < high)
                        arr[high] = arr[low];
        }
        arr[low] = key;
        return low;
}
void quicksort(int arr[], int low, int high){
        if(low < high){
                int index = getIndex(arr,low, high);
                quicksort(arr, low, index - 1);
                quicksort(arr, index+1, high);
        }
}
int main(){
        int a[] = {1,2,4,6,4,2,1};
        quicksort(a, 0, 6);
        for(int i = 0; i < 6; i++){
                cout<< a[i];
        }
        return 0;
}

归并排序


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值