菜菜的题解

1.最大连续子串和

给定一个数列,要求求出这个数列最大的连续子串和(最大和大于等于0)
例如给定 5 3 -9 1 1 2 7
最大子串和为11(1+1+2+7)

题目分析
此问题,采取一种贪心策略,假设有N项,从数列的第一项开始遍历到第M项(M<N),计算从第一项到第M项的和sum,若sum大于0,则无论第M+1项到第N项的和有多大,加上sum都会更大。也就是说,当sum>0时,继续累加,有更大的概率取到最大和。相反的当sum<0时,如果继续累加会减小得到的最大和。所以当sum<0时,应该从第M+1项重新累加。
每累加一次,都要比较sum与当前最大值max(初始化为0)比较。若sum大于max就更新max。
举例
对于样例: 5 3 -9 1 1 2 7
初始化 sum=0,max=0;
M=1 sum=5 (sum>max) max=5
M=2 sum=8 (sum>max) max=8
M=3 sum=-1 (sum<0) 则 sum=0 max=8
M=4 sum=1 (sum<max) max=8
M=5 sum=2 max=8
M=6 sum=4 max=8
M=7 sum=11(sum>max) max=11
最终结果max=11

代码(C++)

#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
using namespace std;
int main() {
    int N; //N储存数组大小
    cin>>N;
    int num;
    int sum=0;
    int max=0;
    for(int i=0; i<N; i++) {
        cin>>num;
        if(sum+num>0) {
            sum=sum+num;
            if(sum>max) {
                max=sum;
            }
        } else {
            sum=0;
        }
    }
    cout<<max;
    return 0;

}

方格填数(DFS)

###问题叙述
在2行5列的格子中填入1到10的数字。
要求:相邻的格子中的数,右边的大于左边的,下边的大于上边的。
如下图所示的2种,就是合格的填法。
在这里插入图片描述
请你计算一共有多少种可能的方案。
###问题分析
这是一道比较典型简单的可以用DFS解决的题目。首先 1和10 的位置一定是左上角和右下角,对于第一列的其他格子的数字,只需满足大于左边的数字即可,对于第二列格子,不仅要大于左边的数字,还要大于上边的数字。并且第二列第一个格子需要单独判断,因为其没有左侧。
由于数据规模不大,用递归的深度优先遍历可以解决

#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
using namespace std;
int visited[10]= {0};//visited数组记录已经被使用的数字,等于0表示未使用,1表示已经使用
int arr[2][6]= {0};//数组模拟表格
int total=0;
void dfs(int k) {
    if(k==10) {
        total++;
    } else {
        if(k<6) {
            for(int i=2; i<10; i++) {
                if(visited[i]==0&&i>arr[0][k-1]) {//k<6时,只需要大于左边
                    arr[0][k]=i;
                    visited[i]=1;
                    dfs(k+1);
                    arr[0][k]=0;
                    visited[i]=0;
                }
            }
        } else if(k==6) {//k==6时只需要大于上边
            for(int i=0; i<10; i++) {
                if(visited[i]==0&&i>arr[0][1]) {
                    arr[1][1]=i;
                    visited[i]=1;
                    dfs(k+1);
                    arr[1][1]=0;
                    visited[i]=0;
                }
            }
        } else {//k大于6时同时满足大于左侧大于上侧
            for(int i=2; i<10; i++) {
                if(visited[i]==0&&i>arr[1][k-6]&&i>arr[0][k-5]) {
                    arr[1][k-5]=i;
                    visited[i]=1;
                    dfs(k+1);
                    arr[1][k-5]=0;
                    visited[i]=0;
                }
            }
        }

    }
}
int main() {
    arr[0][1]=1;
    arr[1][5]=10;//初始化左上角和右下角
    dfs(2);
    cout<<total;
    return 0;

}

##编辑距离(动态规划)
给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符
删除一个字符
替换一个字符
输入: word1 = “horse”, word2 = “ros”
输出: 3
解释:
horse -> rorse (将 ‘h’ 替换为 ‘r’)
rorse -> rose (删除 ‘r’)
rose -> ros (删除 ‘e’)
示例 2:

输入: word1 = “intention”, word2 = “execution”
输出: 5
解释:
intention -> inention (删除 ‘t’)
inention -> enention (将 ‘i’ 替换为 ‘e’)
enention -> exention (将 ‘n’ 替换为 ‘x’)
exention -> exection (将 ‘n’ 替换为 ‘c’)
exection -> execution (插入 ‘u’)

##分析
/数组dp[i][j] 表示对word1的前i个字符进行操作,转换为word2的前j个字符的最小操作次数

主要考虑对第i个字符进行的操作是什么

1.插入操作 从而相等 所以先让前i个字符变为j-1字符,然后在第i处插入j代表的字符 即 dp[i][j] = dp[i][j-1]+1

2 删除操作 从而相等 所以先让前i-1个字符变为j字符,然后在第i处删除 即 dp[i][jj] = dp[i-1][j]+1

3 替换操作 从而相等 if(i处等于j处不需要替换) 即dp[i][j] = dp[i-1][j-1]
// else 需要替换 dp[i][j] = dp[i-1][j-1]+1

上述取个最小值即可

代码(C++)

#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
#include<string>
using namespace std;
int main() {
    string word1,word2;
    cin>>word1>>word2;
    int len1=word1.size();
    int len2=word2.size();
    if(len1==0&&len2==0) {
        return 0;
    }
    int dp[len1+1][len2+1];
    dp[0][0]=0;
    int i,j;
    for(i=j; j<=len2; j++) {//初始化,当word1为空时,只能一直插入字母
        dp[0][j]=j;
    }
    for(i=1; i<=len1; i++) {//当word2为空时,只能一直删除
        dp[i][0]=i;
    }

    for(i=1; i<=len1; i++) {
        for(j=1; j<=len2; j++) {
            if(word1[i-1]==word2[j-1]) {//当前字母相等时,无需操作
                dp[i][j]=dp[i-1][j-1];
            } else {//当前字母不相等时
                dp[i][j]=dp[i-1][j-1]+1;//替换
                if(dp[i-1][j]+1< dp[i][j]) { //删除
                    dp[i][j]=dp[i-1][j]+1;
                }
                if(dp[i][j-1]+1<dp[i][j]) { //插入
                    dp[i][j]=dp[i][j-1]+1;
                }
            }
        }
    }
    cout<<dp[len1][len2];
    return 0;

}


本人菜鸟一枚,第一次写相关类的博客,欢迎各位大佬指正,交流。各位可以尽情的在留言区口吐芬芳。鄙人都虚心接受。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值