题目一:解码方法
一条包含字母 A-Z
的消息通过以下方式进行了编码:
'A' -> 1
'B' -> 2
...
'Z' -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
示例 1:
输入: "12"
输出: 2
解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。
示例 2:
输入: "226"
输出: 3
解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
class Solution {
public int numDecodings(String s) {
char[] chars = s.toCharArray();
//前i个字符的编码个数
int[] dp = new int[chars.length + 1];
dp[0] = 1;
dp[1] = chars[0] == '0' ? 0 : 1;
if(chars.length <= 1)
return dp[1];
for(int i = 2;i <= chars.length;i++){
int n = (chars[i - 2] - '0') * 10 + (chars[i - 1] - '0');
if(chars[i - 1] == '0' && chars[i - 2] == '0'){
//两个都是0,直接退出
return 0;
}else if(chars[i - 2] == '0'){
//原字符串尾是0
dp[i] = dp[i - 1];
}else if(chars[i - 1] == '0'){
//新加入的字符是0
if(n > 26)
return 0;
dp[i] = dp[i - 2];
}else if(n > 26){
dp[i] = dp[i - 1];
}else{
dp[i] = dp[i - 1] + dp[i - 2];
}
}
return dp[dp.length - 1];
}
}
分析:dp[i]代表的是前i个字符的编码方法数。dp[1] = 1,表示只有一个字符时候的编码个数,当然就是1啦。dp[0]=1,表示的意义在于:两个字符时,可以是x y,也可以是xy.dp[2]=dp[1]+dp[0]。接下来对于新加入的字符需要判断以下几种情况。例如:121x y。这个时候x表示前一个字符串尾部的字符,y表示新加入的字符。x = chars[i - 2],y = chars[i - 1]。
(1)如果x = ‘0’ 并且 y = '0'。这样无论如何也满足不了条件的。所以直接返回0。
(2)如果x = '0' 而 y != '0'。那么只能是 1210 y这样的分组。因为0y不符合条件。dp[i] = dp[i - 1]。跟没加入字符的编码个数一样。
(3)如果x != '0'而y = '0'。那么只有121 x0 这样分组。因为单独的0不符合条件,dp[i] = dp[i - 2]。大那是x0如果大于26就直接返回了。编码失败。
(4)如果x != '0'而y != '0',并且n>26。那就必须将xy分开。所以还是跟前一个编码个数相同。dp[i] = dp[i - 1]。
(5)如果都不满足的话,就是可以121x y和121 xy这样的组合。所以dp[i] = dp[i - 1] + dp[i - 2]。
最后返回最后一个值,就是编码个数了。
题目二:不同二叉搜索树
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
class Solution {
public int numTrees(int n) {
int[] arr = new int[n + 1];
arr[0] = 1;
arr[1] = 1;
for(int i = 2;i < arr.length;i++){
for(int j = 1;j <= i;j++){
arr[i] += arr[j - 1] * arr[i - j];
}
}
return arr[n];
}
}
arr[i]表示i序列可以构建不同二叉搜索树的个数。例如:当i = 6的时候,那么就需要将以j = 1,2 ... 6为根节点的不同二叉搜索树的个数相加。这就是里面一层for循环的含义,arr[i] += arr[j - 1] * arr[i - j];的意思是:序列[1, 2, 3, 4, 5, 6, 7],现在j=3。那么就需要算以3为根节点的不同二叉搜索树的个数,左子树[1,2],右子树[4,5,6,7]。由于左右子树与实际的个数并无太大的关系,所以左子树实际就是arr[2],右子树实际就是arr[4](个数与具体数值无关)。然后左右子树相乘,因为这是所有组合的情况。
题目三:三角形最短路径之和
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int[][] temp = new int[triangle.size()][triangle.get(triangle.size()-1).size()];
//初始化
temp[0][0] = triangle.get(0).get(0);
for(int i = 1;i < triangle.size();i++){
temp[i][0] = triangle.get(i).get(0) + temp[i - 1][0];
temp[i][i] = triangle.get(i).get(i) + temp[i - 1][i - 1];
}
//开搞
for(int i = 2;i < temp.length;i++){
for(int j = 1;j < triangle.get(i).size()-1;j++){
temp[i][j] = Math.min(temp[i - 1][j - 1],temp[i - 1][j]) + triangle.get(i).get(j);
}
}
int min = Integer.MAX_VALUE;
for(int i = 0;i < temp[0].length;i++){
if(min > temp[temp.length - 1][i]){
min = temp[temp.length - 1][i];
}
}
return min;
}
}
这个比较简单。大家看看就可以了。
题目四:买股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
class Solution {
public int maxProfit(int[] prices) {
if(prices.length == 0){
return 0;
}
int min = prices[0];
prices[0] = 0;
for(int i = 1;i < prices.length;i++){
if(min > prices[i]){
min = prices[i];
}
prices[i] = prices[i - 1] > prices[i] - min ? prices[i - 1]:prices[i] - min ;
}
return prices[prices.length - 1];
}
}
简单题目。。。