變態青蛙跳臺階
問題描述:
一隻青蛙一次可以跳上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];
}
};