1.什么是动态规划:
大问题可分解成子问题,问题之间不独立,一般用数组保存记录值,不用递归是因为递归会使得重复计算,而动态递归不同于分治法的一点就是可以利用之前求出的解,不需要从头来。
(1)解法:
1.找出最优子结构
2.找出状态转换方程
3.给边界赋值
2.题目(力扣)
(1).121. 买卖股票的最佳时机
最优子结构:
状态转换方程:
class Solution {
public int maxProfit(int[] prices) {
//思路:前i天的最大盈利=MAX(前i-1天的最大营利,第i天的价格-前i-1天的最小价格)
int result=0;
int min=0;
int []max=new int[prices.length];
min=prices[0];
for(int i=1;i<prices.length;i++){
max[i]=Math.max(max[i-1],prices[i]-min);
if(min>prices[i]){
min=prices[i];
}
}
return max[prices.length-1];
}
}
(2)找零钱问题:
思路其实跟爬楼梯一样
状态转移方程为:
countMin[i]=Math.min(count[i-1],count[i-3],count[i-7])+1;
package com.company;
public class Main {
//有零钱1/3/7元的,求找零钱的数目最少。
public static void main(String[] args) {
int count=change(17);
System.out.println(count);
}
public static int change(int value){
if(value==1||value==3||value==7){
return 1;
}
else{
int []count=new int[value+1];
count[0]=0;
count[1]=1;
count[3]=1;
count[7]=1;
for(int i=2;i<=value;i++){
if(i-3<0){
count[i]=count[i-1]+1;
}
else if(i-7<0){
count[i]=Math.min(count[i-1],count[i-3])+1;
}
else{
int min=Math.min(count[i-1],count[i-3]);
count[i]=Math.min(min,count[i-7])+1;
}
}
return count[value];
}
}
}
(3)303. 区域和检索 - 数组不可变
class NumArray {
int [] nums;
int [][] count;
public NumArray(int[] nums) {
this.nums=nums;
count=new int[nums.length][];
}
public int sumRange(int left, int right) {
if(count[left]!=null){
return count[left][right-left];
}
else{
count[left]=new int[nums.length-left];
count[left][0]=nums[left];
for(int j=1;j<nums.length-left;j++){
count[left][j]=count[left][j-1]+nums[left+j];
}
return count[left][right-left];
}
}
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* int param_1 = obj.sumRange(left,right);
*/
法二:直接每次都求
class NumArray {
int[] nums;
public NumArray(int[] nums) {
this.nums=nums;
}
public int sumRange(int left, int right) {
int sum=0;
for(int i=left;i<=right;i++){
sum+=nums[i];
}
return sum;
}
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* int param_1 = obj.sumRange(left,right);
*/
法三:法一中的二维变一维度:
class NumArray {
int[] nums;
int []count;
public NumArray(int[] nums) {
this.nums=nums;
count=new int[nums.length+1];
for(int i=0;i<nums.length;i++){
if(i==0){
count[i]=nums[i];
}
else{
count[i]=count[i-1]+nums[i];
}
}
}
public int sumRange(int left, int right) {
if(left>0){
return count[right]-count[left-1];
}
else{
return count[right];
}
}
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* int param_1 = obj.sumRange(left,right);
*/
不用再新开数组,直接nums数组原地求和即可
class NumArray {
int[] nums;
public NumArray(int[] nums) {
this.nums=nums;
for(int i=1;i<nums.length;i++){
nums[i]+=nums[i-1];
}
}
public int sumRange(int left, int right) {
if(left>0){
return nums[right]-nums[left-1];
}
else{
return nums[right];
}
}
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* int param_1 = obj.sumRange(left,right);
*/