最大子数组和
爬楼梯
杨辉三角《一》《2》
// 1
// 1 1
// 1 2 1
// 1 3 3 1
// 1 4 6 4 1
// 1 5 10 10 5 1
//
// f(i)(j) = f(i-1)f(j-1)+f(i)f(j-1)
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> result = new ArrayList<>();
int[][] array = new int[numRows][numRows];
for(int i = 0;i<numRows;i++){
List<Integer> list = new ArrayList<Integer>();
for(int j = 0;j<=i;j++){
if(j==0||j==i){
array[i][j]=1;
}else{
array[i][j]=array[i-1][j-1]+array[i-1][j];
}
list.add(array[i][j]);
}
result.add(list);
}
return result;
}
}
// 1
// 1 1
// 1 2 1
// 1 3 3 1
// 1 4 6 4 1
// 1 5 10 10 5 1
//
// f(i)(j) = f(i-1)f(j-1)+f(i)f(j-1)
2、121. 买卖股票的最佳时机
两个动态规划方程
// 动态规划 前i天的最大收益 = max{前i-1天的最大收益,第i天的价格-前i-1天中的最小价格}
class Solution {
public int maxProfit(int[] prices) {
int maxProfit =0;
int minValue = Integer.MAX_VALUE;
for(int price:prices){
if(price<minValue){
minValue = price;
}else{
maxProfit = Math.max(price-minValue,maxProfit);
}
}
return maxProfit;
}
}
状态定义方法:将第i天卖出股票可以获得的最大利润定义为dp[i],然后求解,代码如下:
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int res = 0;
// 前一天卖出可以获得的最大利润
int pre = 0;
for (int i = 1; i < len; i++) {
// 利润差
int diff = prices[i] - prices[i - 1];
// 状态转移方程:第i天卖出可以获得的最大利润 = 第i-1天卖出的最大利润 + 利润差
pre = Math.max(pre + diff, 0);
res = Math.max(res, pre);
}
return res;
}
}
public class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
// 特殊判断
if (len < 2) {
return 0;
}
int[][] dp = new int[len][2];
// dp[i][0] 下标为 i 这天结束的时候,不持股,手上拥有的现金数
// dp[i][1] 下标为 i 这天结束的时候,持股,手上拥有的现金数
// 初始化:不持股显然为 0,持股就需要减去第 1 天(下标为 0)的股价
dp[0][0] = 0;
dp[0][1] = -prices[0];
// 从第 2 天开始遍历
for (int i = 1; i < len; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
}
return dp[len - 1][0];
}
}
338. 比特位计数
1、常规的暴力破解方法
class Solution {
public int[] countBits(int n) {
int[] result = new int[n+1];
for(int i=0;i<=n;i++){
result[i] = countOnes(i);
}
return result;
}
public int countOnes(int x){
int one= 0;
while(x>0){
x = x&(x-1);
one++;
}
return one;
}
}
2、状态转移方程
class Solution {
public int[] countBits(int n) {
int[] dp = new int[n+1];
for(int i=0;i<=n;i++){
if (i%2==0) {
dp[i]=dp[i/2];
} else {
dp[i]=dp[i/2]+1;
}
}
return dp;
}
}
菲波那切数列-滚动数组
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
class Solution {
public int fib(int n) {
if(n<2){
return n;
}
int p = 0;
int q = 0;
int r = 1;
for(int i=2;i<=n;i++){
p=q;
q=r;
r=p+q;
}
return r;
}
}
花费最小的代码爬楼梯
class Solution {
public int minCostClimbingStairs(int[] cost) {
int size = cost.length;
int[] dp = new int[size+1];
dp[0] = 0;
dp[1] = 0;
for(int i=2;i<=size;i++){
dp[i] = Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
}
return dp[size];
}
}
// 首先要推递归方程
// f(0) = 0 ; f(1) =0
// f(n) = Min(f(n-1)+cost[n-1],f(n-2)+cost[n-2])
第 N 个泰波那契数
泰波那契序列 Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
给你整数 n,请返回第 n 个泰波那契数 Tn 的值。
class Solution {
public int tribonacci(int n) {
int[] dp = new int[n+1];
if(n==0){
return 0;
}
if(n==1){
return 1;
}
if(n==2){
return 1;
}
dp[0] =0;
dp[1] =1;
dp[2] =1;
for(int j=3;j<dp.length;j++){
dp[j] = dp[j-1] + dp[j-2] + dp[j-3];
}
return dp[n];
}
}
获取生成数组中的最大值
class Solution {
public int getMaximumGenerated(int n) {
int[] dp = new int[n+1];
if(n==0){
return 0;
}
if(n==1){
return 1;
}
int max = 1;
dp[0]=0;
dp[1]=1;
for(int j=2;j<=n;j++){
if(j%2==0){
dp[j] =dp[j/2];
}else{
dp[j] = dp[j/2]+dp[j/2+1];
}
max = (dp[j]>max)?dp[j]:max;
}
return max;
}
}
下载插件
令 dp[i] 表示下载 i 个插件需要的最少分钟数,则 dp[i] = dp[(i + 1) / 2] + 1;
剑指 Offer 10- II. 青蛙跳台阶问题
class Solution {
public int numWays(int n) {
if(n==0){
return 1;
}
if(n==1){
return 1;
}
int[] dp = new int[n+1];
dp[0]=1;
dp[1]=1;
for(int i=2;i<=n;i++){
dp[i] = (dp[i-1] + dp[i-2])%(1000000007);
}
return dp[n]%(1000000007);
}
}
// 动态规划方程
// f(0)=0
// f(1)=1
// f(2)=2
// f(n)=f(n-1)+f(n-2)
连续子数组的最大和
class Solution {
public int maxSubArray(int[] nums) {
int size = nums.length;
int[] dp = new int[size];
int max = nums[0];
dp[0] = nums[0];
for(int i=1;i<size;i++){
dp[i] = Math.max(dp[i-1]+nums[i],nums[i]);
max = dp[i]>max?dp[i]:max;
}
return max;
}
}
// 连续子数组的最大和
// Max(f(i-1)+cost[i],cost[i])
面试题 08.01. 三步问题
class Solution {
public int waysToStep(int n) {
if(n==1){
return 1;
}
if(n==2){
return 2;
}
if(n==3){
return 4;
}
int[] dp = new int[n+1];
dp[1]=1;
dp[2]=2;
dp[3]=4;
for(int i=4;i<=n;i++){
dp[i] = ((dp[i-1]+dp[i-2])%(1000000007)+dp[i-3])%(1000000007);
}
return dp[n]%(1000000007);
}
}
// 动态规划方程
// f(n)=f(n-1)+f(n-2)+f(n-3)
面试题 17.16. 按摩师
class Solution {
public int massage(int[] nums) {
int len = nums.length;
if(len==0){
return 0;
}
if(len==1){
return nums[0];
}
// dp[i][0]:区间[0,i]里接收预约请求,并且下标为i的这一天不接受预约
// dp[i][1]:区间[0,i]里接收预约请求,并且下标为i的这一天接收预约
int[][] dp = new int[len][2];
dp[0][0] =0;
dp[0][1] = nums[0];
for(int i=1;i<len;i++){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]);
dp[i][1] = dp[i-1][0] + nums[i];
}
return Math.max(dp[len-1][0],dp[len-1][1]);
}
}
翻转数位
class Solution {
public int reverseBits(int num) {
int[] current = new int[32];
int[] reverse = new int[32];
int max = 0;
if((num&1)==1){
current[0]=1;
reverse[0]=1;
}else{
current[0]=0;
reverse[0]=1;
}
num=num>>1;
for(int i=1;i<32;i++){
if((num&1)==1){
current[i]=current[i-1]+1;
reverse[i]=reverse[i-1]+1;
}else{
current[i]=0;
reverse[i]=current[i-1]+1;
}
if(reverse[i]>max){
max = reverse[i];
}
num=num>>1;
}
return max;
}
}
// current[i] 表示包含第i位的从num二进制低位至第i位联系1的最长长度
// reverse[i] 表示包含第i位的从低位到第i位最多翻转1个0->1的连续1的最长长度
// 用num[i] 表示整数num第i位的值
// 遍历num所有位数,也就是32位,reverse数组中最大值就是答案
// 转态方程
// current[i]= num[i]==1?current[i-1]+1:0;
// reverse[i]= num[i]==1?reverse[i-1]+1:current[i-1]+1
除数博弈
class Solution {
public boolean divisorGame(int n) {
if(n==1){
return false;
}
if(n==2){
return true;
}
boolean[] flag = new boolean[n+1];
flag[1] = false;
flag[2] = true;
for(int i=3;i<=n;i++){
for(int j=1;j<i;j++){
if((i%j==0)&&(!flag[i-j])){
flag[i] =true;
break;
}
}
}
return flag[n];
}
}
// 爱丽丝先开局
判断子序列
1.双指针
class Solution {
public boolean isSubsequence(String s, String t) {
// s是子序列
int m = s.length();
// t是非子序列
int n = t.length();
int i = 0;
int j = 0;
while(i<m&&j<n){
if(s.charAt(i)==t.charAt(j)){
j++;
}
i++;
}
return j==m;
}
}
2、动态规划方法
class Solution {
public boolean isSubsequence(String s, String t) {
int n = s.length(), m = t.length();
int[][] f = new int[m + 1][26];
for (int i = 0; i < 26; i++) {
f[m][i] = m;
}
for (int i = m - 1; i >= 0; i--) {
for (int j = 0; j < 26; j++) {
if (t.charAt(i) == j + 'a')
f[i][j] = i;
else
f[i][j] = f[i + 1][j];
}
}
int add = 0;
for (int i = 0; i < n; i++) {
if (f[add][s.charAt(i) - 'a'] == m) {
return false;
}
add = f[add][s.charAt(i) - 'a'] + 1;
}
return true;
}
}
传递信息
class Solution {
public int numWays(int n, int[][] relation, int k) {
int[][] dp = new int[k + 1][n];
dp[0][0] = 1;
for (int i = 0; i < k; i++) {
for (int[] edge : relation) {
int src = edge[0], dst = edge[1];
dp[i + 1][dst] += dp[i][src];
}
}
return dp[k][n - 1];
}
}