LeeCode刷题总结(二)

LeeCode刷题总结(二)

前言
用leecode题目练手,练习编码的感觉。先从简单题开始,刷完后和知识点结合总结。
先刷简单题,对遇到的问题类型和不知道的知识点先列举。有空闲时间继续归类到《算法总结》。

经过LeeCode刷题总结(一)的c++语法和基本数据结构的掌握后,对简单题总的算法举例总结。

c++基本容器数据结构中使用最多的vector、string、TreeNode、ListNode,基本操作需要掌握。


递推

由前几项循环递推出第n项

//#118 杨辉三角 #119杨辉三角||
class Solution {
public:
    vector<vector<int>> generate(int numRows) {       
        vector<vector<int>> ans;
        int i=0;
        while(i++<numRows){ 
            vector<int> Now(i,1);
            if(i>2){
                for(int j=1;j<i-1;j++)Now[j]= ans[i-2][j-1]+ans[i-2][j];              
            }ans.push_back(Now);
        }
        return ans;
    }
};

递归

算f(n)规模的结果需要使用f(n-1)的结果

n的前几项有固定结果为初始值

计算机实现利用的是栈空间

//#38 外观数列  
//求解n的问题要先求解n-1的问题。
//递归代码最神的地方, 一个循环可以展现出n个嵌套for循环的作用, 可以好好体会
class Solution {
public:
    string countAndSay(int n) {    
        if(n==1) return "1";//1、初始条件,n==1
        string ans = countAndSay(n-1);//2、递归函数n=f(n-1)
        //3、已知n的返回值ans,来求解n+1的返回值now,n从初始条件1开始
        //注意为什么是求解n+1的问题,n从1开始?因为递归的入参是n-1,最后的返回结果是求解n
        string now; 
        int len = ans.length();
        int j=0;//记录下标
        for(int i=1;i<len+1;i++){
            //最后一个元素要单独处理
            if((ans[j]!=ans[i])||(i==len)){
                //now += to_string(i-j)+ans[j]; //运算效率低很多
                now.push_back(i-j+'0');
                now.push_back(ans[j]);
                j=i;
            }
        }
        return now;
    }
};
#100 相同的树;#101 对称二叉树;#104 二叉树的最大深度;#108 将有序数组转换为二叉搜索树;#110 平衡二叉树;#104 二叉树的最大深度;
**这些简单的二叉树问题无一例外,转换成本节点和左右子节点的递归运算**

动态规划

每次保存的值都在循环滚动
Dp本质还是迭代,总要有一个迭代的初值。正向迭代不是递归

//#70 爬楼梯 最简单的动态规划
class Solution {
public:
    int climbStairs(int n) {
        if(n<3)return n;
        int i1=1;
        int i2=2;
        int temp;
        for(int i=3;i<=n;i++){
            temp=i1+i2;
            i1=i2;
            i2=temp;
        }
        return i2;     
    }
};
/*
递推超时,必须转动态规划怎么转?
动态规划是值都在变化,不一定是递归.3个值都在滚动相加。
递归从后往前推,一直到n=1/n=2,之前的子集求解多遍,
动态规划从前往后推,从n=1/n=2累计,保存每次的总数更新。
*/
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size()==1)return 0;
        int ans=0;
        int min=prices[0];
        for(int i=1;i<prices.size();i++){
            ans=max(ans,prices[i]-min);
            if(prices[i]<min)min=prices[i];
        }
        
        return ans;
    }
};

/*
嵌套循环又超时...需要想优化的方法,
提示动态规划:第i天的最大收益=max(第i-1天的最大收益,前i-1天的值减最小值)
思路不够清晰的地方:第i-1天的最大收益,不用递归还是正推的DP
*/

双指针

ListNode的题目比较多,fast slow

//#141 判断链表是否有环,理解“这是因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合”是关键。
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head==NULL)return false;
        bool ans=false;

        ListNode *fast=head;
        ListNode *slow=head;
		//一次需要判断两个步长
        while(fast&&fast->next){
            slow=slow->next;
            fast=fast->next->next;             
            if(fast==slow){
                ans =true;
                break;
            }
        }
        return ans;
    }
};
/*
算法优化O(1),快慢指针指针相遇则有环。
理解一下:这是因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合。
*/
posted @ 2021-03-04 14:21  wuya178  阅读(65)  评论(0)    收藏  举报