变态青蛙跳台阶
问题描述:
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多
少种跳法。
思想:
利用排列组合的思想,将台阶分为两部分,前n-1是一部分,最后一节是一部分。则
前面的台阶有两种选择:跳或者不跳,最后一节台阶只有一种选择,必须跳
F(n)=f(n-1)+f(n-2)+....f(n-n)
F(n-1)=f(n-2)+f(n-3)+...+f(n-n)
F(n)=2*f(n-1)*1
import java.util.*;
public class Main {
public static int fun(int n) {
int total=1;
if(n<=0){
return 0;
}
for(int i=1;i<n;i++){
total*=2;
}
return total;
}
public static void main(String[]args) {
Scanner sc=new Scanner(System.in);
int m=sc.nextInt();
int ret=fun(m);
System.out.println(ret);
}
}
矩形覆盖
问题描述
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
思路:
有两种放的方式:
横着放
一个矩形不能构成完整的矩形:F(i-2)种方法
竖着放
一个矩形就可以构成一个完整的矩形:F(i-1)种方法
特殊情况:当n等1时,有一种方法,等2时,有两种方法
import java.util.*;
public class Main {
public static int fugai(int n) {
if(n==1||n==2){
return n;
}
return fugai(n-1)+fugai(n-2);
}
public static void main(String[]args) {
Scanner sc=new Scanner(System.in);
int m=sc.nextInt();
int ret=fugai(m);
System.out.println(ret);
}
}
最大连续子序列和
问题描述:
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
思路:看成两部分,前i-1项和第i项,前i-1项加上第i项的和与第i项做比较,取最大值,换言之,如果前i-1项和为负数,则最后取第i项,保证取得值最大,最后再取所有连续子序列和最大值
public static int maxSum(int a[]) {
int sum=a[0];
int maxsum=a[0];
for(int i=1;i<a.length;i++){
sum=Math.max(sum+a[i],a[i]);
maxsum=Math.max(sum,maxsum);
}
return maxsum;
}
字符串分割
问题描述:
给定一个字符串和一个词典dict,确定s是否可以根据词典中的词分成 一个或多个单词。
思路:还是将字符串看作两部分,看作前 j 部分和后 j~i-1部分,确定能分割条件是:前 j 部分能在字典中找到,后j~i-1部分也能在字典中找到
public class Main{
public boolean wordBreak(String s, List<String> wordDict) {
int n = s.length(); //这里输入都是非空的,n >= 1
boolean[] opt = new boolean[n + 1];
opt[n] = true; //opt[i]表示从i到n - 1的子串是否为wordBreak。opt[n]初始化为true
for (int i = n - 1; i >= 0; i--) {
opt[i] = false;
for (String item : wordDict) {
if (s.indexOf(item, i) == i) {
opt[i] = opt[i] || opt[i + item.length()];
}
//如果已经为true就可以不用再匹配wordDict里的字符串了
if (opt[i]) {
break;
}
}
}
return opt[0];
}
}
三角矩阵
问题描述:
一个三角形矩阵,从第一个元素到最后一个元素得路径最小值
思想:
每个数字可以走得都是它的所在列和后一列。
(i, j) ---> (i+1,j),(i+1,j+1)
(i, j) <---- (i-1,j),(i-1,j-1)
分为三种情况:
F(i,j)=min(f(i-1,j),f(i-1,j-1))+a[i][j]
F(i,0)=f(i-1,0)+a[i][0]
F(i,i)=f(i-1,i-10+a[i][i]
最后取 min(F(i,j)).
public int minimumTotal(List<List<Integer>> triangle){
int[] []dp = new int[triangle.size() + 1][triangle.size() + 1];
for (int i = triangle.size() - 1; i >= 0; i--) {
for (int j = 0; j <i; j++) {
dp[i][j] = Math.min(dp[i-1][j], dp[i-1][j + 1]) + dp[i][j];
}
}
return dp[0][0];
}
路径总数
问题描述:在一个m*n的网格的左上角有一个机器人,机器人在任何时候只能向下或者向右移动,
机器人试图到达网格的右下角,有多少可能的路径。
思路:因为机器人只能向下和向右走,所以只需要知道到达第 (m-1,n)和第 (m,n-1)个元素的方法数即可。还是利用动态思想的方法,将路径看成两部分
状态:
子状态:从(0,0)到达(1,0),(1,1),(2,1),...(m-1,n-1)的路径数
F(i,j): 从(0,0)到达F(i,j)的路径数
状态递推:
F(i,j) = F(i-1,j) + F(i,j-1)
初始化:
特殊情况:第0行和第0列
F(0,i) = 1
F(i,0) = 1
返回结果:
F(m-1,n-1)
class Solution {
public:
int uniquePaths(int m, int n) {
if (m < 1 || n < 1) {
return 0;
}
// 申请F(i,j)空间,初始化
vector<vector<int> > ret(m, vector<int>(n, 1));
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
// F(i,j) = F(i-1,j) + F(i,j-1)
ret[i][j] = ret[i - 1][j] + ret[i][j - 1];
}
}
return ret[m - 1][n - 1];
}
};
最小路径和:
题目描述:
给定一个m*n的网格,网格用非负数填充,找到一条从左上角到右下角的最短路径。
注:每次只能向下或者向右移动。
思路:还是看成两部分路径,前i-1,第i个。
状态:
子状态:从(0,0)到达(1,0),(1,1),(2,1),...(m-1,n-1)的最短路径
F(i,j): 从(0,0)到达F(i,j)的最短路径
状态递推:
F(i,j) = min{F(i-1,j) , F(i,j-1)} + (i,j)
初始化:
F(0,0) = (0,0)
特殊情况:第0行和第0列
F(0,i) = F(0,i-1) + (0,i)
F(i,0) = F(i-1,0) + (i,0)
返回结果:
F(m-1,n-1)
class Solution {
public:
int minPathSum(vector<vector<int> > &grid) {
// 如果为空或者只有一行,返回0
if (grid.empty() || grid[0].empty()) {
return 0;
}
// 获取行和列大小
const int M = grid.size();
const int N = grid[0].size();
// F(i,j)
vector<vector<int> > ret(M, vector<int>(N, 0));
// F(0,0), F(0,i), F(i,0)初始化
ret[0][0] = grid[0][0];
for (int i = 1; i != M; ++i) {
ret[i][0] = grid[i][0] + ret[i - 1][0];
}
for (int i = 1; i != N; ++i) {
ret[0][i] = grid[0][i] + ret[0][i - 1];
}
// F(i,j) = min{F(i-1,j) , F(i,j-1)} + (i,j)
for (int i = 1; i < M; ++i) {
比特科技
for (int j = 1; j < N; ++j) {
ret[i][j] = grid[i][j] + min(ret[i - 1][j], ret[i][j - 1]);
}
}
return ret[M - 1][N - 1];
}
};