• 算法注意---2、遇到算法里面一些不懂的代码怎么办


    算法注意---2、遇到算法里面一些不懂的代码怎么办

    一、总结

    一句话总结:

    代码有疑问的位置,带点实例在程序里面debug一下,代码每句的意思就异常清楚了

    1、枚举法的核心关键?

    对于枚举法,弄清楚枚举变量、枚举范围、枚举判断条件之后,代码非常好写,结合算法思路,的确非常棒

    2、枚举非空数字连续子段的时候,因为我们的设定是起点终点都包含了,所以就算是非空段,终点也不是起点加1,而是起点?

    终点也不是起点加1,而是起点,这样终点和起点一样的时候,字串就是1个


    枚举变量:每一段的起点、终点
    枚举范围:起点:1-n,终点:起点 - n
    枚举判断条件:
    求和得到每一段的和,在这些和里面选出最大的

    3、C++ min,max所在头文件?

    C++ min,max所在头文件 algorithm

    4、遇到算法里面一些不懂的代码怎么办?

    代码有疑问的位置,带点实例在程序里面debug一下,代码每句的意思就异常清楚了

    5、分治(二分、递归)为什么可以求最大连续子序列的和(为什么可以枚举所有解)?

    求解的过程也就是求解下面1、2、3三种情况,情况2是要求的,情况1和3由递归的终止条件可以得到最初解
    ①完全处于序列的左半:l<=i<=j<=mid
    ②完全处于序列的右半:mid<=i<=j<=r
    ③跨越序列中间:i<=mid<=j<=r
    
    这就是分治为什么在函数主体中只进行了第二种情况的计算
    分治在缩小范围的过程中,必然转化为第二种情况
    不是这样,而是转化成1/2/3三种情况,
    情况2要求,情况1和3由递归的终止条件可以得到最初解
    
    //分治求最大连续子序列的和的时候
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int a[200005];
    //分治(二分)求最大连续子序列的和
    int find(int l,int r){
        if(l==r) return a[l];
        int mid=(l+r)/2;
        //1、计算第二种跨越mid情况的序列的最大和
        //a、求以mid为尾的子序列的最大和
        int maxx1=-0x7fffffff;
        int sum1=0;
        for(int k=mid;k>=l;k--){
            sum1+=a[k];
            maxx1=max(sum1,maxx1);
        }
    
        //b、求以mid为头的子序列的最大和
        int maxx2=-0x7fffffff;
        int sum2=0;
        for(int k=mid;k<=r;k++){
            sum2+=a[k];
            maxx2=max(sum2,maxx2);
        }
    
        //2、比较方式1、2、3的最大值
        return max(max(find(l,mid),find(mid+1,r)),maxx1+maxx2-a[mid]);
    }
    
    int main(){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        cout<<find(1,n)<<endl;
        return 0;
    }

    6、分治一般用递归,递归里面真正的核心代码就是递推表达式?

    a、无论是分治里面的二分查找,核心代码是判断查找,然后左右递归
    b、还是分治做求最大连续子序列的和,核心代码是递归的递推表达式,也就是比较方式1、2、3的最大值,左边和右边的可以递归算出,中间的只能自己算出
    ①完全处于序列的左半:l<=i<=j<=mid
    ②完全处于序列的右半:mid<=i<=j<=r
    ③跨越序列中间:i<=mid<=j<=r
    
    //分治求最大连续子序列的和的时候
    #include<cstdio>
    int n , arr[200200]; //arr存储该序列 
    const int minn = -19260817; // 定义最小值 
    inline int Max( int a , int b) { return a > b ? a : b ;} //自定义 Max 函数(好像比stl的快一点) 
    int rec( int l , int r ) { //分治函数 
        if ( l == r ) {    //    l=r时,直接返回该位置的值 
            return arr[l];
        }
        int mid = ( l + r )/2;  
        int sum = 0 , ret1 = minn , ret2 = minn; //ret1为[l..mid]区间内包含mid的最大子段和,ret2为[mid+1..r]区间内包含(mid+1)的最大子段和  
        for( int i = mid ; i >= l ; i-- ) {
            //就是普普通通的找最大的代码
            //而且找的是以mid结尾的串的最大和
            sum += arr[i];
            ret1 = Max( ret1 , sum );
        }  //求出[1..mid]区间最大值
        sum = 0;
        for( int i = mid+1 ; i <= r ; i++ ) {
            //就是普普通通的找最大的代码
            //这个显然是找的以mid+1开头的序列的最大和
            sum += arr[i];
            ret2 = Max( ret2 , sum );
        }  //求出[mid+1..r]区间最大值
        return Max( Max( rec( l , mid ) , rec( mid + 1 , r ) ) , ret1 + ret2 );   //返回可能一 可能二 可能三 中的最大值
    }

    7、递归的终止条件和递归的递推表达式在递归中的真正作用(分治做递归理解)?

    递归的终止条件其实是在配合递推表达式的基础上,给向左向右的递归提供初始值,
    递归的递推表达式其实是递归中的核心代码,一般都特别少(一般一个式子)

    8、递归做分治注意点:求最大连续子序列的和?

    a、递归的终止条件:因为我们的递归是为了求l到r序列的子序列的最大值,所以当区间只有一个元素时,就是终止条件,那个元素就是子序列的最大值
    b、递归的递推表达式:比较方式1、2、3的最大值,而第2种跨越mid值的需要我们去计算,1,3种到了递归的终止条件,自然有解
    c、递归的返回值:子序列的最大值
    ①完全处于序列的左半:l<=i<=j<=mid
    ②完全处于序列的右半:mid<=i<=j<=r
    ③跨越序列中间:i<=mid<=j<=r
    
    //分治求最大连续子序列的和的时候
    #include<cstdio>
    int n , arr[200200]; //arr存储该序列 
    const int minn = -19260817; // 定义最小值 
    inline int Max( int a , int b) { return a > b ? a : b ;} //自定义 Max 函数(好像比stl的快一点) 
    int rec( int l , int r ) { //分治函数 
        if ( l == r ) {    //    l=r时,直接返回该位置的值 
            return arr[l];
        }
        int mid = ( l + r )/2;  
        int sum = 0 , ret1 = minn , ret2 = minn; //ret1为[l..mid]区间内包含mid的最大子段和,ret2为[mid+1..r]区间内包含(mid+1)的最大子段和  
        for( int i = mid ; i >= l ; i-- ) {
            //就是普普通通的找最大的代码
            //而且找的是以mid结尾的串的最大和
            sum += arr[i];
            ret1 = Max( ret1 , sum );
        }  //求出[1..mid]区间最大值
        sum = 0;
        for( int i = mid+1 ; i <= r ; i++ ) {
            //就是普普通通的找最大的代码
            //这个显然是找的以mid+1开头的序列的最大和
            sum += arr[i];
            ret2 = Max( ret2 , sum );
        }  //求出[mid+1..r]区间最大值
        return Max( Max( rec( l , mid ) , rec( mid + 1 , r ) ) , ret1 + ret2 );   //返回可能一 可能二 可能三 中的最大值
    }

    9、包含mid的子序列很好求?

    即求出区间[i..mid]的最大值maxx1与区间[mid..j]的最大值maxx2,将其合并即可,即maxx1+maxx2-a[mid]


    其中,很容易求出第二种情况,第二种情况也就是包含mid的子序列,
    也就是[i...mid...j],而求[i...mid...j]的最大值,
    即求出区间[i..mid]的最大值与区间[mid..j]的最大值,将其合并即可。

    10、求最长子序列的和,为什么可以用分治?

    其实无论是分左分右,还是包含mid的整个,所有的区间都会被枚举到


    ①完全处于序列的左半:l<=i<=j<=mid
    ②完全处于序列的右半:mid<=i<=j<=r
    ③跨越序列中间:i<=mid<=j<=r


    二、内容在总结中

    博客对应课程的视频位置:

     
  • 相关阅读:
    UVALive 5066 Fire Drill --BFS+DP
    Codeforces 486E LIS of Sequence --树状数组求LIS
    Codeforces 460D Little Victor and Set --分类讨论+构造
    Codeforces Round #285 (Div.1 B & Div.2 D) Misha and Permutations Summation --二分+树状数组
    计算机组成原理知识总结
    HDU 5155 Harry And Magic Box --DP
    【Python数据分析】简单爬虫 爬取知乎神回复
    《查拉图斯特拉如是说》读书笔记
    POJ 3384 Feng Shui --直线切平面
    POJ 2540 Hotter Colder --半平面交
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/13029092.html
Copyright © 2020-2023  润新知