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