剑指offer-动态规划算法

  • Post author:
  • Post category:其他


问题1、连续子数组的最大和

//给定数组{1,-2,3,10,-4,7,2,-5},则连续子数组的的最大和范围为{3,10,-4,7,2}
//解法一、直接写
int FindGreatestSumOfSubArray(int a[],int n){
    int sum=0;
    int temp=0;
    for(int i=0;i<n;i++){
        if(sum<=0){
            sum=a[i];
        }
        else{
            sum+=a[i];
        }
        if(temp<sum){
            temp=sum;
        }
    }
    return temp;
}
//解法二、动态规划
int FindGreatestSumOfSubArray(int a[], int n){

    int *f = new int[n+1];
    memset(f, 0, sizeof(f));
    int maxSum=0;
    for (int i = 0; i<n; i++){
        if (i == 0 || f[i - 1] <= 0){
            f[i] = a[i];
        } else{
            f[i] = f[i - 1] + a[i];
        }
        if (maxSum<f[i])
            maxSum = f[i];
    }
   return maxSum;
}

问题2、钢条切割问题。给定钢条长度,为了获取最优收益,求解最优切割方案

//长度:1  2  3  4  5  6  7  8  9  10  
//价格:1  5  8  9  10 17 17 20 24 30
int CutRod(int a[], int n){
    if (n==0)   return 0;
    int q=-1000;
    for (int i = 0; i<n; i++){
        q = max(q,a[i]+CutRod(a,n-i-1));
    } 
    return q;
}
//可以用带备忘录的方式计算,避免重复递归求解相同子问题
//带备忘的自顶向下
memset(memory_p,-1,11*sizeof(int));
emory_p[0]=0;
int cut_rod_memory(int prices[], int len){
    if(len==0)      return 0;
    if(memory_p[len]>=0)    return memory_p[len];//查询是否已经求出对应的部分最优解
    int sum=INT_MIN;
    for(int i=1;i<=len;i++)
    {
            sum=max(sum,prices[i-1]+cut_rod(prices,len-i));
    }
    memory_p[len]=sum;     //保存每一次的结果,大力提升速度(空间换时间)
    return sum;
}

问题3、求解两个字符串的最长公共子串

string LongestSubstring(string str1,string str2){
    int len1=str1.size();
    int len2=str2.size();
    //f[i][j]表示到str1[i]=str[j]之前的相同数目
    int **f=new int*[len1+1];
    for(int i=0;i<len2;i++)
            f[i]=new int[len2+1];
    memset(&(f[0][0]),0,siszeof(int)*(len1+1)*(len2+1));
    int index=1;
    int sum=0;
    for(int i=0;i<len1;i++){
        for(int j=0;j<len2;j++)
        {
            if(str1[i]==str2[j])
                f[i+1][j+1]=f[i][j]+1;
            else 
                f[i+1][j+1]=0;          
            if(sum<f[i+1][j+1]){
                    index=i+1;
                    sum=f[i+1][j+1];
            }
        }
    }
    int last=index-1;
    return str1.substr(last-sum-1,sum);
}

问题4、求两个字符串的最长公共子序列

void PrintLCS(char **b,string s,int len1,int len2){
    if(len1==0||len2==0)    return ;
    if(b[len1][len2]=='Y'){
        PrintLCS(b,s,len1-1,len2-1);
        cout<<s[len1-1];
    }else if(b[len1][len2]=='|')
    {
        PrintLCS(b,s,len1-1,len2);
    }else
    {
        PrintLCS(b,s,len1,len2-1);
    }
}
void LCS(string s1,string s2){
    int n1=s1.size();
    int n2=s2.size();
    int **c=new int*[n1+1];//保存LCS长度
    char **p=new char*[n1+1];   //保存路径
    for(int i=0;i<n1+1;i++){
            c[i]=new int[n2+1];
    }
    for(int i=0;i<n1+1;i++){
            p[i]=new char[n2+1];
    }
    memset(&(c[0][0]),0,sizeof(int)*(n1+1)*(n2+1));//清零操作

    for(int i=1;i<n1+1;i++){

        for(int j=1;j<n2+1;j++){
            if(s1[i-1]==s2[j-1]){
                c[i][j]=c[i-1][j-1]+1;
                p[i][j]='Y';
            }
            //此时的LCS即为前期已经确定下来的LCS,比较取得最大的
            else if(c[i-1][j]>=c[i][j-1])
            {
                c[i][j]=c[i-1][j];
                p[i][j]='|';
            }else
            {
                c[i][j]=c[i][j-1];
                p[i][j]='-';
            }
        }
    }
    PrintLCS(p,s1,n1,n2);
}

问题3、最长回文字符串

string LongestPalindromestring(string str){

        int len=str.size();
        bool f[100][100];
        memset(&(f[0][0]),false,sizeof(f));
        int start=0;
        int maxLen=1;
        for(int i=0;i<len;i++){//i表示终点
            f[i][i]=true;
            for(int j=0;j<i;j++){
                if(j+1==i&&str[i]==str[j]){
                        f[j][i]=true;
                }else if(j+1<i&&str[i]==str[j]){
                        f[j][i]=f[j+1][i-1];
                }else{
                    f[j][i]=false;
                }

                if(f[j][i]&&maxLen<i-j+1){
                    maxLen=i-j+1;
                    start=j;
                }
            }
        }
        return str.substr(start,maxLen);
}

特别注意:memset和fill_n一般不能对申请的堆空间进行清零。



版权声明:本文为southernriver原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。