import uitls.Node;
import uitls.TreeNode;
import java.util.Arrays;
import java.util.Stack;
public class test_02_25 {
//动态规划21题
//爬楼梯-动态规划
public static int test6(int n){
//建立dp数组
int[] dp= new int[n];
//初始化dp数组
dp[0]=1;
dp[1]=2;
//进行状态转移
for (int i=2;i<n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n-1];
}
//爬楼梯-采取动态规划O(1)
public static int test7(int n){
int a=1;
int b=2;
for (int i=3;i<=n;i++){
int temp=a;
a=b;
b=temp+b;
}
return b;
}
//爬楼梯-递归
public static int test8(int n){
if (n==1){
return 1;
}
if (n==2){
return 2;
}
return test7(n-1)+test7(n-2);
}
//路径问题
public static int test9(int[][] arr){
int n=arr.length;
int m=arr[0].length;
//建立dp数组
int[][] dp=new int[n][m];
//初始化dp数组
for (int i=0;i<n;i++){
dp[i][0]=1;
}
for (int i=0;i<m;i++){
dp[0][i]=1;
}
//进行状态转移
for (int i=1;i<n;i++){
for (int j=1;j<m;j++){
//只能从上面或者从左边走过来
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[n-1][m-1];
}
//不同路径-存在障碍物
public static int test10(int[][] arr){
int n=arr.length;
int m=arr[0].length;
//建立dp数组
int[][] dp=new int[n][m];
//初始化dp数组
dp[0][0]=1-arr[0][0];
if (dp[0][0]==1){
return 0;
}
//进行状态转移
for (int i=0;i<n;i++){
for (int j=0;j<m;j++){
//判断一下是不是第一行
if (i==0&&j>0){
//处理第一行
if (arr[0][j]==1){
dp[0][j]=0;
}else{
dp[0][j]=dp[0][j-1];
}
}else if (i>0&&j==0){
//处理第一列
if (arr[i][0]==1){
dp[i][0]=0;
}else {
dp[i][0]=dp[i-1][0];
}
}else if (i>0&&j>0){
//不处理原点 非第一行且非第一列
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
}
return dp[n-1][m-1];
}
//最小路径和
public static int test11(int[][] grid){
int n=grid.length;
int m=grid[0].length;
//建立dp数组
int[][] dp=new int[n][m];
//初始化dp数组
dp[0][0]=grid[0][0];
//状态转移
for (int i=0;i<n;i++){
for (int j=0;j<m;j++){
//处理第一行
if (i==0&&j>0){
dp[0][j]=dp[0][j-1]+grid[i][j];
}else if (j==0&&i>0){
//处理第一列
dp[i][0]=dp[i-1][0]+grid[i][j];
}else if (i>0&&j>0){
dp[i][j]=dp[i-1][j]+dp[i][j-1]+grid[i][j];
}
}
}
return dp[n-1][m-1];
}
//三角形的最小路径和 找出最小的路径之和-只能由自己的上面或者左上角
//2
//3 4
//6 5 7
//4 1 8 3
public static int test12(int[][] arr){
int n=arr.length;
int m=arr[0].length;
//建立dp数组
int[][] dp= new int[n][m];
dp[0][0]=arr[0][0];
//进行状态转移 只要求下三角就可以
for (int i=0;i<n;i++){
for (int j=0;j<=i;j++){
//进行判断 第一行
if (i>0&&j==0){
dp[i][j]=dp[i-1][j]+arr[i][j];
}else if (i==j&&i>0&&j>0){
//对角线 保证不是第一个值
dp[i][j]=dp[i-1][j-1]+arr[i][j];
}else if (i>0&&j>0&&j<i){
dp[i][j]=Math.min(dp[i-1][j-1],dp[i-1][j])+arr[i][j];
}
}
}
int minValue = dp[n-1][0];
for (int i=1;i<m;i++){
if (dp[n-1][i]<minValue){
minValue=dp[n-1][i];
}
}
return minValue;
}
//买卖股票[7 1 5 3 6 4]
public static int test13(int[] arr){
int n=arr.length;
//建立dp数组 一个针对于卖出 一个买入
int[][] dp=new int[n][2];
//初始化dp数组
//卖出的利润
dp[0][0]=0;
//买入的利润
dp[0][1]=-arr[0];
//建立状态转移方程
for (int i=1;i<n;i++){
//卖出 则为上次买入价格+这次卖出价格,上次卖出价格
dp[i][0] = Math.max(dp[i-1][1]+arr[i],dp[i-1][0]);
//买入 这次买入和上次买入的最小值
dp[i][1]=Math.max(-arr[i],dp[i-1][1]);
}
return dp[n-1][0];
}
//买卖股票I-优化-采取
public static int test14(int[] arr){
//采取两个变量
int a = 0;
int b=-arr[0];
//进行状态转移
for (int i=1;i<arr.length;i++){
//卖出
a=Math.max(b+arr[i],a);
//买入
b=Math.max(-arr[i],b);
}
return a;
}
//买卖股票的最佳时机II-无线次交易
public static int test15(int[] arr){
int sum=0;
for (int i=0;i<arr.length-1;i++){
if (arr[i+1]>arr[i]){
sum+=arr[i+1]-arr[i];
}
}
return sum;
}
//买卖股票的最佳时机II-无线次交易-采取状态机
public static int test16(int[] arr){
int[][] dp= new int[arr.length][2];
dp[0][0]=0;
dp[0][1]=-arr[0];
for (int i=1;i<arr.length;i++){
//卖出的利润
//昨天买入的利润+今天卖出的钱,昨天卖出的利润
dp[i][0]=Math.max(dp[i-1][1]+arr[i],dp[i-1][0]);
//买入的利润
//昨天卖出的利润-今天买入的钱,昨天买入的利润
dp[i][1]=Math.max(dp[i-1][0]-arr[i],dp[i-1][1]);
}
return dp[arr.length-1][0];
}
//买卖股票的最佳时机III
public static void test17(int[] arr){
//只有五种状态
//1:一笔都没有买入 2:买入一笔 没有卖出 3:买入一笔并卖出一笔 4:买入两笔,卖出一笔 5:买入两笔并卖出
int n=arr.length;
int[][] dp=new int[n][5];
//2:进行初始化
dp[0][0]=0;
dp[0][1]=-arr[0];
//保证dp[i][2]=Math.max(dp[i-1][1]+arr[i],dp[i-1][2]);这里的状态能正确转移
dp[0][2]=-arr[0];
dp[0][3]=0;
dp[0][4]=0;
//3:进行状态转移
for (int i=1;i<n;i++){
//买入一笔
dp[i][1]=Math.max(-arr[i],dp[i-1][1]);
//买入一笔并卖出
dp[i][2]=Math.max(dp[i-1][1]+arr[i],dp[i-1][2]);
//买入两笔,卖出一笔
dp[i][3]=Math.max(dp[i][2]-arr[i],dp[i-1][3]);
//买入两笔并卖出
dp[i][4]=Math.max(dp[i][3]+arr[i],dp[i-1][4]);
}
}
//TODO 买卖股票-可以交易K次
//打家劫舍问题[1,2,3,1]
public static void test19(int[] arr){
int n=arr.length;
//建立dp数组
int[] dp=new int[n];
//初始化dp数组
dp[0]=arr[0];
dp[1]=Math.max(dp[0],arr[1]);
//进行状态转移
for (int i=2;i<n;i++){
dp[i]=Math.max(arr[i]+dp[i-2],dp[i-2]);
}
}
//打家劫舍-首尾相连
public static int test20(int[] arr){
int n=arr.length-1;
int[] dp=new int[n];
dp[0]=arr[0];
dp[1]=Math.max(dp[0],arr[1]);
//进行状态转移
for (int i=2;i<n;i++){
dp[i]=Math.max(dp[i-2]+arr[i],dp[i-1]);
}
dp[0]=arr[1];
dp[1]=Math.max(dp[0],arr[2]);
int x=dp[n-1];
for (int i=2;i<n;i++){
dp[i]=Math.max(dp[i-2]+arr[i+1],dp[i-1]);
}
return Math.max(x, dp[n-1]);
}
//打家劫舍问题III-就是不能同时盗窃子父两个房子
public static int[] test21(TreeNode root){
if (root==null){
return new int[]{0,0};
}
int[] left = test21(root.getLeft());
int[] right = test21(root.getLeft());
return new int[]{left[1]+right[1]+root.getData(),
Math.max(left[0],left[1])+Math.max(right[0],right[1])};
}
//回文子串-统计有多少个回文子串-一个串中有多少个回文子串
public static int test22(String s){
int n = s.length();
int[][] dp = new int[n][n];
for (int i=0;i<n;i++){
dp[i][i]=1;
}
//从对角线到左上角
for (int k=0;k<n;k++){
int i=0;
while (i+k+1<n){
//是回文串
if (test23(s, i, i+k+1)){
dp[i][i+k+1]=dp[i][i+k]+dp[i+1][i+k+1]-1+1;
}else{
dp[i][i+k+1]=dp[i][i+k]+dp[i+1][i+k+1]-1;
}
i++;
}
}
return dp[0][n-1];
}
//判断是不是回文子串
public static boolean test23(String s, int i, int j){
while (i<j){
if (s.charAt(i) != s.charAt(j)) {
return false;
}
i++;
j--;
}
return true;
}
//最长回文子串-暴力解法
public static String test24(String s){
int n=s.length();
//dp[i]表示以i结尾的最长回文子串大小
int[] dp=new int[n];
//找出最长回文子串
for (int i=0;i<n;i++){
int max=1;
for (int j=i;j>=0;j--){
//是回文子串
if (test23(s,j,i)){
max=i-j+1;
}
}
dp[i]=max;
}
int max=1;
int maxIndex = 0;
for (int i=1;i<n;i++){
if (dp[i]>max){
max=dp[i];
maxIndex=i;
}
}
return s.substring(maxIndex-max,maxIndex+1);
}
//最长回文子串-动态规划
public static String test25(String s){
int n=s.length();
//建立dp数组
boolean[][] dp = new boolean[n][n];
//初始化dp数组
for (int i=0;i<n;i++){
dp[i][i]=true;
}
for (int k=1;k<n;k++){
int i=0;
if (s.charAt(i)==s.charAt(i+k)&&k==1){
//第二个对角
dp[i][i+k]=true;
}else if (s.charAt(i)!=s.charAt(i+k)&&k==1){
dp[i][i+k]=false;
}else if (s.charAt(i)==s.charAt(i+k)&&k!=1){
dp[i][i+k]=dp[i+1][i+k-1];
}else if (s.charAt(i)!=s.charAt(i+k)&&k!=1){
dp[i][i+k]=false;
}
}
int max = 1;
int maxIndex = 0;
for (int i=0;i<n;i++){
for (int j=i;j<n;j++){
if (dp[i][j]&&j-i+1>max){
max=j-i+1;
maxIndex=j;
}
}
}
return s.substring(maxIndex-max,maxIndex+1);
}
//最长回文子序列
public static int test26(String s){
int n=s.length();
//建立dp数组
int[][] dp=new int[n][n];
for (int i=0;i<n;i++){
dp[i][i]=1;
}
for (int i=0;i<n-1;i++){
if (s.charAt(i)==s.charAt(i+1)){
dp[i][i+1]=2;
}else{
dp[i][i+1]=1;
}
}
for (int k=2;k<n;k++){
int i=0;
while (i+k<n){
//相等
if (s.charAt(i)==s.charAt(i+k)){
dp[i][i+k]=dp[i+1][i+k-1];
}else{
dp[i][i+k]=Math.max(dp[i][i+k-1],dp[i+1][i+k]);
}
i++;
}
}
return dp[0][n-1];
}
//最大子序和
public static int test27(int[] nums){
int n = nums.length;
//建立dp数组
int[] dp=new int[n];
dp[0]=nums[0];
//进行状态转移
for (int i=1;i<n;i++){
//找出以这个结尾的最大和
dp[i]=Math.max(nums[i],dp[i-1]+nums[i]);
}
return dp[n-1];
}
//最大子序和-采取O(1)的时间复杂度
public static int test28(int[] nums){
//存储上一个数的最大和
int a= Math.max(0,nums[0]);
//存储选择上一个数或者
int b = nums[0];
for (int i=1; i<nums.length;i++){
//以这个结尾的最大和
b=Math.max(b+nums[i],nums[i]);
//从a和b中找出最大值
a=Math.max(b,a);
}
return a;
}
//最长递增子序列
public static int test29(int[] nums){
int n=nums.length;
//建立dp数组
int[] dp=new int[n];
//初始化dp数组
dp[0]=1;
//进行状态转移
for (int i=1;i<n;i++){
int max=1;
//从后往前找出最大的
for (int j=i-1;j>=0;j--){
if (nums[i]>nums[j]){
max=Math.max(dp[j]+1,max);
}
}
dp[i]=max;
}
return Arrays.stream(dp).max().getAsInt();
}
//乘积最大的子数组-连续的
public static int test30(int[] nums){
int n=nums.length;
//找出乘积最大的连续子数组
//建立dp数组 dp[i]表示以这个结尾的最大乘积
int[] dp=new int[n];
//初始化dp数组
dp[0]=nums[0];
//状态转移
for (int i=1;i<n;i++){
dp[i]=Math.max(dp[i-1]*nums[i],nums[i]);
}
return Arrays.stream(dp).max().getAsInt();
}
//最长重复子数组-看左上角
public static int test31(int[] A, int[] B){
int n=A.length;
int m=B.length;
//建立dp数组
int[][] dp= new int[n][m];
//初始化dp数组
for (int i=0;i<n;i++){
if (A[i]==B[0]){
dp[i][0]=1;
}else{
dp[i][0]=0;
}
}
for (int i=0;i<m;i++){
if (A[0]==B[i]){
dp[0][i]=1;
}else{
dp[0][i]=0;
}
}
//进行状态转移
for (int i=1; i<n;i++){
for (int j=1;j<m;j++){
if (A[i]==B[j]){
dp[i][j]=Math.max(dp[i-1][j-1]+1,Math.max(dp[i-1][j],dp[i][j-1]));
}else{
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
return dp[n-1][m-1];
}
//爬楼梯
public static int test32(int n){
//建立dp数组
int[] dp= new int[n];
//初始化dp数组
dp[0]=1;
dp[1]=2;
//进行状态转移
for (int i=2;i<n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n-1];
}
//最大正方形-找出只包含1的正方形-暴力破解法
public static int test33(int[][] arr){
int n = arr.length;
int m=arr[0].length;
//找出最小的边
int z = Math.min(n,m);//z=4 n=4 m=5
while (z-->0){
//进行求解 不能到边界
for (int i=0;i<n-z;i++){
for (int j=0;j<m-z;j++){
boolean b = test34(arr, i, j, z);
//如果找到了
if (b){
return z;
}
}
}
}
//没有找到
return -1;
}
//判断是不是正方形
public static boolean test34(int[][] arr, int i, int j, int size){
for (int m=i;m<i+size;m++){
for (int n=j;n<j+size;n++){
if (arr[m][n]!=1){
return false;
}
}
}
return true;
}
//采取动态规划
public static int test35(int[][] arr){
int n=arr.length;
int m = arr[0].length;
int[][] dp=new int[n][m];
//初始化dp数组
for (int i=0;i<n;i++){
dp[i][0]=1;
}
for (int i=0;i<m;i++){
dp[0][i]=1;
}
int res = 0;
//进行状态转移
for (int i=1;i<n;i++){
for (int j=1;j<m;j++){
//表明为1
if (arr[i][j]==1){
dp[i][j]=Math.max(dp[i-1][j],Math.min(dp[i][j-1],dp[i-1][j-1]))+1;
res=Math.max(dp[i][j],res);
}
}
}
return res;
}
//接雨水-采取一个栈进行求解
public static void test36(int[] arr){
Stack<Integer> stack = new Stack<>();
int i=0;
while (arr[i]==0){
i++;
}
//存储第一个节点
stack.push(i);
int sum=0;
for (int j=i+1;j<arr.length;j++){
//查看当前栈顶元素下标
Integer peek = stack.peek();
if (arr[j]>arr[peek]){
//开始计算雨水
Integer pop = stack.pop();
//只有当栈不为空时才计算
if (!stack.isEmpty()){
//栈不为空
Integer left = stack.peek();
//进行累加
sum += (Math.min(arr[j],arr[left])-arr[pop])*(j-left-1);
//判断当前元素是否大于当前栈顶元素
j--;
}else{
//入栈当前j
stack.push(j);
}
}else if(arr[j]<arr[peek]){
//小于 直接入栈
stack.push(j);
}
}
System.out.println(sum);
}
public static void main(String[] args) {
int i = test33(new int[][]{
{1, 0, 1, 0, 0},
{1, 0, 1, 1, 1},
{1, 1, 1, 1, 1},
{1, 0, 0, 1, 0}
});
System.out.println(i);
}
//树递归六种
//七种排序
//两种二分-非递归
public static int test1(int[] nums, int target){
int left=0;
int right = nums.length-1;
while (left<=right){
int mid = (left+right);
if (nums[mid]>target){
right=mid-1;
}else if(nums[mid]<target){
left=mid+1;
}else{
return mid;
}
}
return -1;
}
public static int test2(int[] nums, int target){
return test3(nums, 0, nums.length - 1, target);
}
public static int test3(int[] nums, int left, int right, int target){
if (left>right){
return -1;
}
int mid = (left+right)/2;
if (nums[mid]>target){
return test3(nums, left, mid-1, target);
}else if (nums[mid]<target){
return test3(nums, mid+1, right, target);
}else{
return mid;
}
}
//链表反转-两题
public static Node test4(Node head){
Node pre=null;
Node p=head;
Node pp = head.getNext();
while (pp!=null){
p.setNext(pre);
pre=p;
p=pp;
pp=pp.getNext();
}
p.setNext(pre);
return p;
}
//链表反转递归
public static Node test5(Node head){
//如果判定到倒数第一个节点 则直接返回这个节点 作为头节点
if (head.getNext()==null){
return head;
}
//返回一个新的头节点 返回最后递归的一个节点
Node newHead = test5(head.getNext());
head.getNext().setNext(head);
//将这个节点设置为null
head.setNext(null);
return newHead;
}
}
算法刷题-动态规划21题+链表9题-2025年02月25日上午
最新推荐文章于 2026-08-22 14:49:29 发布

20万+

被折叠的 条评论
为什么被折叠?



