2021最新Java大厂面试题来袭,初识动态规划

本文深入探讨了动态规划的概念,将其定义为通过分解问题并存储子问题的解决方案来解决复杂问题的方法。文章列举了多个动态规划的经典案例,如Fibonacci数列、青蛙跳台阶、矩阵覆盖、最大连续子数组和、字符串分割和三角矩阵求最短路径等,并详细解释了每个问题的状态定义、转移方程和解决方案。此外,文章还强调了动态规划在Java后端面试中的重要性,并提供了全面的Java面试题资源链接,帮助求职者提升技能,准备面试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态规划就是分治的思想,通俗一点就是大事化小,小事化了。并且在将大问题化解为小问题的时候,保存对这些小问题处理好的结果,供后面处理更大规模问题去使用。

动态规划的特点:

1.把原来的问题分解成了几个相似的子问题

2.所有子问题只需要解决一边

3.存储子问题的解

动态规划问题解决步骤

动态规划的本质,是对问题状态的定义和状态方程的定义。

1.状态定义

2.状态间的转移方程定义

3.状态的初始化

4.返回结果(解或者间接解)

状态定义的要求:定义的状态一定要形成递推关系

适用场景最大最小值,可不可行,是不是,方案个数等问题。

一、Fibonacci数列

================================================================================

先对问题进行分析

1.状态定义: F(n)

2.状态间的转移方程:F(n)=F(n-1)+F(n-2);

3.状态的初始化:(初始值) F(0)=0; F(1)=1;

4.返回结果:F(n)

代码如下(示例):


 public static int Fib(int n){

        if(n<=0){

            return 0;

        }

        //从第零项开始所以多开辟一个空间

        int []dp=new int[n+1];

        dp[0]=0;

        dp[1]=1;

        for(int i=2;i<=n;i++){

            //状态转移方程

            //F(n)=F(n-1)+F(n-2)

            dp[i]=dp[i-1]+dp[i-2];

        }

        return dp[n];

   	} 

当然我们也可以不使用数组让空间复杂度达到O(1)


public static int Fib1(int n){

        if(n<=0){

            return 0;

        }

        if(n==1||n==2){

            return 1;

        }

        int f1=1;

        int f2=1;

        int f3=0;

        for(int i=3;i<=n;i++){

            f3=f1+f2;

            f1=f2;

            f2=f3;

        }

        return f3;

    } 

很多动规问题都可以转化成Fib数列解决

二、青蛙跳台阶

==========================================================================

先是变态青蛙跳台阶,有n阶台阶,青蛙可以每次跳一个,二个…或者n个

分解问题:

1.状态定义F(n)

2.状态间转移方程定义 F(n)=2F(n-1)

3.状态的初始化 F(1)=1

4.返回结果 F(n)


 public static int climbingStairs(int n){

			 int res=1;

        for(int i=2;i<=n;i++){

            //F(n)=2F(n-1)

            res*=2;

        }

        return res;

} 

之后是正常的青蛙,每次只能跳一个台阶或者两个台阶(斐波那契数列)

leetcode 70题

1.状态定义 F(n)

2.状态间转移方程定义F(n)=F(n-1)+F(n-2)

3.状态初始化 F(1)=1;

4.返回结果 F(n)


 public static int climbingStairs1(int n){

    	if(n==1||n==2){

      		 return n;

      	}

          int f1=1;

          int f2=2;

          int f3=0;

          for(int i=3;i<=n;i++){

              f3=f1+f2;

              f1=f2;

              f2=f3;

          }

          return f3;

} 

三、矩阵覆盖

=========================================================================

题目链接

分析问题后依旧是斐波那契数列

1.状态定义 F(n)

2.状态间转移方程定义 F(n)=F(n-1)+F(n-2)

3.状态的初始化 F(1)=1 F(2)=2

4.返回结果 F(n)


 public static int rectCover(int target) {

    if(target==1||target==2){

            return target;

        }

        int t1=1;

        int t2=2;

        int t3=0;

        for(int i=3;i<=target;i++){

            t3=t1+t2;

            t1=t2;

            t2=t3;

        }

        return t3;

	}

} 

或者使用数组记录


public static int rectCover1(int target){

        if(target==0){

            return 0;

        }

        int []dp=new int[target+1];

        dp[0]=1;

        dp[1]=2;

        for(int i=2;i<target;i++){

            dp[i]=dp[i-1]+dp[i-2];

        }

        return dp[target-1];

} 

四、最大连续字数组和

=============================================================================

leetcode 53题

这种题使用动态规划来做的话就和前面几个不相同了,因为其无法定义状态间转移方程

所以就把大问题化成先问题去解决

例如求最大连续字数组和,先求前i个最大字数组的和,最终求最大连续字数组和

时间复杂度O(n),空间复杂度O(1)做法


public int maxSubArray(int[] nums) {

      int res=nums[0];

     for(int i=1;i<nums.length;i++){

     //比较当前值和当前值加上前一个值的大小

    nums[i]=Math.max(nums[i-1]+nums[i],nums[i]);

           res=Math.max(nums[i],res);

        }

        return res;

   } 

或者另外一种如果前i项最大子序和<=0就重新赋值为下一个数值,记录max最大值


public static int maxSubArray(int[] nums) {

        int max=nums[0];

        int count=nums[0];

        for(int i=1;i<nums.length;i++){

            if(count<=0){

                count=nums[i];

            }else {

                count+=nums[i];

            }

          max=Math.max(max,count);

       }

        return max;

    } 

五、字符串分割

==========================================================================

题目链接

先把大问题化成小问题 前i个字母能否成功分割

状态转移方程是 j<i&&F(j)&&[j,i-1] 即F(j)为true [j,i-1]也为true 这样可以存储true

例如:给定s=“nowcode” 已知 now 和code 在词典中,在找到cow后就可以从j+1位置找到 i位置单词是否能在词典中找到

举例说明:

例如dict 中 [le ,et ,co ,de]是单词

那么当leetcode字符串传来时

F(1) false ——— F(2) true ——— F(3)false ————F(4)true

F(5) false——— F(6) true ——— F(7)false ——— F(8) true

即判断时可以借助前面的结果来判断 例如F(4)利用F(2)为true 只需要判断后两个字母是否能组成单词即可。


 public boolean wordBreak(String s, Set<String> dict) {

            if(s.length()==0){

                return true;

            }

           boolean[]array=new boolean[s.length()+1];

       		 for(int i=1;i<=s.length();i++){

            //1~i整体范围是一个单词

            if(dict.contains(s.substring(0,i))){//substring 是从0到i-1位置

                array[i]=true;

                continue;

            }

            for(int j=i-1;j>0;j--){

                //部分判断 一部分为前面验证过的true 判断后面的也为true

                if(array[j]&&dict.contains(s.substring(j,i))){//substring 是从j位置到i-1位置

                    array[i]=true;

                    break;

                }

            }

        }

        return array[s.length()];

        } 

leetcode 139题

也是这样的字符串拆分 双80%


 public boolean wordBreak(String s, List<String> wordDict) {

 boolean []array=new boolean[s.length()+1];

            for(int i=1;i<=s.length();i++){

                if(wordDict.contains(s.substring(0,i))){

                    array[i]=true;

                    continue;

                }

                for(int j=i-1;j>0;j--){

                    if(array[j]&&wordDict.contains(s.substring(j,i))){

                        array[i]=true;

                        break;

                    }

                }

            }

            return array[s.length()];

     } 

六、三角矩阵求最短路径

==============================================================================

牛客题目链接

leetcode 120题

给定一个三角矩阵,找出自顶向下的最短路径和,每一步可以移动到下一行相邻的数字

首先确定相邻元素的概念:

1.如果在F(i,j)下一行相邻元素就是 (i+1,j)(i+1,j+1)

如果从下往上推的话,从F(i,j)位置往上的相邻位置就是(i-1,j)(i-1,j-1)

2.状态转移方程是 F(min)=Math.min(F(i-1,j),(i-1,j-1))+a(i,j)// 从相邻位置中找到最小值,之后加上当前位置坐标

注意每一行的第一列和最后一列只有一条路径

第一列F(i,0)=F(i-1,0)+a[i][0]

最后一列 F(i,i)=F(i-1,i-1)+a[i][i]

3.初始状态

F(0,0)=a[0][0]

最终思想是从上往下求(先判断边界情况,第一列只有一条路径,最后一列也只有一条路径都加上当前坐标值就好,)之后找最小路径值就可以了。


public int minimumTotal(List<List<Integer>> triangle) {

         List<List<Integer>> list=new ArrayList<>();

        for(int i=0;i<triangle.size();i++){

            list.add(new ArrayList<>());

        }

        //先定义初始值 在0位置加上(0,0)坐标的值

        list.get(0).add(triangle.get(0).get(0));

        //之后遍历判断特殊情况  每一行的第一个 ,每一行的最后一个

        for(int i=1;i<triangle.size();i++){

            int count=0;//当前路径和

            for(int j=0;j<=i;j++){

            if(j==0){

            count=list.get(i-1).get(j);

            }else if(i==j){

                count=list.get(i-1).get(j-1);

                }else {

                count=Math.min(list.get(i-1).get(j),list.get(i-1).get(j-1));

            }

           list.get(i).add(triangle.get(i).get(j)+count);

            }

        }

        //之后找到list中到目标路径的最小值即可

        int len=triangle.size();

        int min=list.get(len-1).get(0);

        for(int i=1;i<len;i++){

            min=Math.min(min,list.get(len-1).get(i));

        }

        return min;

    } 

七、不同路径

=========================================================================

最后

即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!

CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】

我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!
一共有20个知识点专题,分别是:

Dubbo面试专题

JVM面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Java并发面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Kafka面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MongDB面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MyBatis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MySQL面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Netty面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

RabbitMQ面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Redis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Spring Cloud面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

SpringBoot面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

zookeeper面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

常见面试算法题汇总专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

计算机网络基础专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

设计模式专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南
18067267)]

MyBatis面试专题

[外链图片转存中…(img-6bvUUT6e-1630718067268)]

MySQL面试专题

[外链图片转存中…(img-20oPg2SJ-1630718067268)]

Netty面试专题

[外链图片转存中…(img-ZSZAilq7-1630718067269)]

RabbitMQ面试专题

[外链图片转存中…(img-fC7rArcg-1630718067270)]

Redis面试专题

[外链图片转存中…(img-c86Vmq5j-1630718067270)]

Spring Cloud面试专题

[外链图片转存中…(img-su2BotZm-1630718067271)]

SpringBoot面试专题

[外链图片转存中…(img-NQDR5cYZ-1630718067272)]

zookeeper面试专题

[外链图片转存中…(img-mdJVG4x2-1630718067272)]

常见面试算法题汇总专题

[外链图片转存中…(img-tBJ0g1cV-1630718067273)]

计算机网络基础专题

[外链图片转存中…(img-8mtVcOB9-1630718067274)]

设计模式专题

[外链图片转存中…(img-5OT0Eb0q-1630718067274)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值