先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:xhs1999xhs (备注Java)
正文
👨🎓作者简介:一位喜欢写作,计科专业大二菜鸟
🏡个人主页:starry陆离
🕒首发日期:2022年5月16日星期一
🌌上期文章:【动态规划】最长上升子序列
📚订阅专栏:算法分析与设计
如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦
【背包问题】01背包问题
1. 问题描述
给定n种物品(每种物品只有一件)和一个背包:物品i的重量是wi,其价值 为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物 品的总价值最大?
对于每种物品,只有两种选择:装(1)或者不装(0),不允许装物品的一部分
因此有这么一个著名的公式:
找出物品选择的组合的重量总和要不大于背包的容量为C,且要找出这些组合中装入背包中物品的总价值的最大的组合
2. 问题分析
如果穷举这些组合,我们知道每一个物品都有选和不选,则一共有2 n(n是物品的种类);然后去除这些组合中大于背包的容量为C的组合,再找总价值最大的即为解;显然这个数量级太大了
2.1 减少规模
定义
m(i,j)
是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值则
m(i+1,j)
为可选择物品为i+1,…,n时0-1背包问题的最优值。。。依次类推
m(n,j)
为可选择物品为n时0-1背包问题的最优值,此时,规模已为1
即当可选物品为n时,背包容量为j,如果此时的背包容量能装下第n个物品,那么m(n,j)
的最优值就是第n个物品的价值vn,装不下那就是0;(因为现在的可选物品只有第n个)
2.2 推导递归式
判断是否放入第i件?
1)不放,背包当前产生价值仍为
m(i+1,j)
2)放入,调整背包容量j-wi,背包当前产生价值为m(i+1, j-wi)+vi
结合两式即可得:
3 填DP表
已知n=5, c=10, w={2, 2, 6, 5, 4}, v={6, 3, 5, 4, 6}
绘制m[i,j]的最下面两行
思路:
- 由上面的分析可知,我们是从下往上,从左往右填dp表,
- 如m(5,10)就是表示背包容量为10时,可选择物品为n时的最优值,而我们最终的解就是m(1,10)的值
- 首先由第一个公式填最后一行m(5,j)(0<=j<10)
- 然后有第二个公式填剩下的表格
4 图解算法
剩下的两行也是用同样的方法递推,读者可自己完成,理解这个逻辑过程
5 代码实现
时间复杂度:O(nc)(n是物品种类,c是背包容量)
空间复杂度:S(nc)
private static int DpSolve(int n, int c, int[] w, int[] v, int[][] dp) {
//初始化第n行
for(int j=0;j<=c;++j) {
if(j>=w[n]) {
//System.out.println("w[n]="+w[n]);
dp[n][j]=v[n];
}
}
//动态规划
for(int i=n-1;i>=1;i--) {
for(int j=1;j<=c;++j) {
if(j<w[i]) {
dp[i][j]=dp[i+1][j];
}else {
dp[i][j]=Math.max(dp[i+1][j], dp[i+1][j-w[i]]+v[i]);
}
}
}
return dp[1][c];
}
6. 构造最优解
能够求出01背包问题的最优值,我们如何求出一个最优解呢?
如上面的问题的最优解为1-》2-》5,如果用1代表选择物品,0代表不选择,那么结果可表示为11001
这个结果是如何得出的呢?
- 只需要当前的m(i,j)和它的下面的最优值m(i+1,j)比较,
- 如果两者相等说明没有选择物品i,因为价值没有增加
- 如果两者不相等说明选择了物品i,则需要把当前的背包容量j减去物品i的重量w(i),得出m(i+1,j-w(i)),其意义在于找到装入物品i前的背包能取得的最优值;
- 同理依次类推,循环执行第一步,直到找到倒数第二个物品是否选择
- 最后一步单独判断最后一个物品有没有选择,如果m(n,j)==0则表示没选择最后一个,不为0说明选择了
如上面的问题的最优解为1-》2-》5,如果用1代表选择物品,0代表不选择,那么结果可表示为11001
只需要当前的m(i,j)和它的下面的最优值m(i+1,j)比较,
- 如果两者相等说明没有选择物品i,因为价值没有增加;
- 如果两者不相等说明选择了物品i,则需要把当前的背包容量j减去物品i的重量w(i),得出m(i+1,j-w(i)),其意义在于找到装入物品i前的背包能取得的最优值;
同理依次类推,循环执行第一步,直到找到倒数第二个物品是否选择
最后一步单独判断最后一个物品有没有选择,如果m(n,j)==0则表示没选择最后一个,不为0说明选择了
private static void Gouzao(int n, int c, int[] w, int[] v, int[][] dp) {
for(int i=1;i<n;++i) {
if(dp[i][c]==dp[i+1][c]) {
//相等说明没选,输出0
System.out.print("0");
}else {
//不相等说明选择了,输出1
System.out.print("1");
//更新背包的容量,要减去第i个物品的重量
//准备去找装入物品i前的背包能取得的最优值
c=c-w[i];
}
}
//处理最后一个物品
int last=(dp[n][c]>0?1:0);
System.out.println(last);
}
7. 练习题
原题地址:https://acm.hnucm.edu.cn/JudgeOnline/
题目描述
给定n种物品和一个背包,物品i的重量是Wi,其价值为Vi,背包的容量为C。如何选择装入背包的物品,可以使得装入背包中物品的总价值最大?
输入
每组输入包括三行,
第一行包括物品个数n,以及背包容量C。
第二、三行包括两个一维数组,分别为每一种物品的价值和重量。输出
输出包括两行,第一行为背包的最大总价值,第二行为所选取的物品。
例如:最大总价值=15,物品选取策略为11001。数据保证答案唯一。样例输入
5 10 6 3 5 4 6 2 2 6 5 4
样例输出
15 11001
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n;
int c;
int[] w,v;
int[][] dp;
while(scanner.hasNext()) {
n=scanner.nextInt();
c=scanner.nextInt();
w=new int[n+1];
v=new int[n+1];
dp=new int[n+1][c+1];
for(int i=1;i<=n;++i) {
v[i]=scanner.nextInt();
}
for(int i=1;i<=n;++i) {
w[i]=scanner.nextInt();
}
for(int j=0;j<=c;++j) {
if(j>=w[n]) {
dp[n][j]=v[n];
}
}
//动态规划
for(int i=n-1;i>=1;i--) {
for(int j=1;j<=c;++j) {
if(j<w[i]) {
dp[i][j]=dp[i+1][j];
}else {
dp[i][j]=Math.max(dp[i+1][j], dp[i+1][j-w[i]]+v[i]);
}
}
}
int ans=dp[1][c];
System.out.println(ans);
Gouzao(n,c,w,v,dp);
}
}
private static void Gouzao(int n, int c, int[] w, int[] v, int[][] dp) {
for(int i=1;i<n;++i) {
if(dp[i][c]==dp[i+1][c]) {
System.out.print("0");
}else {
System.out.print("1");
c=c-w[i];
}
}
int last=(dp[n][c]>0?1:0);
System.out.println(last);
}
}
8. 扩展:空间压缩
我们注意到每次递推第i行都是用下面一行(第i+1行)的最优值,如果只用一个一维数组dp[]来存储这些值,那么
递推第i行前,
dp[i]=m(i+1,j)
递推第i行后,
dp[i]=m(i,j)
(覆盖掉原来的值)
而在计算递推第i行时的m()数组的值,有两种选择变化:
1)不放,背包当前产生价值仍为
m(i+1,j)
,即dp[i]保持不变2)放入,调整背包容量j-wi,背包当前产生价值为m(i+1, j-wi)+vi,即dp[j]=dp[j-wi]+vi
但是求解dp[]数组时,必须保证dp[j-wi]还是m(i,j-wi)的值,考虑到每次递推都会覆盖掉原来dp[]数组中的值,如当j的值从小往大变化,即我们从左往右求解时dp[j-wi]已经是m(i+1,j-wi)的值了;(读者可自行推演,如果这样上一题的答案会是30)
因而我们得从右往左求解,即j从大往下变化
//动态规划
for(int i=n;i>=1;i--) {
//j从大往下变化,保证dp[j-wi]还是m(i,j-wi)的值
for(int j=c;j>=0;--j) {
if(j>=w[i]) {
dp[j]=Math.max(dp[j], dp[j-w[i]]+v[i]);
}
}
}
最后我们该如何学习?
1、看视频进行系统学习
这几年的Crud经历,让我明白自己真的算是菜鸡中的战斗机,也正因为Crud,导致自己技术比较零散,也不够深入不够系统,所以重新进行学习是很有必要的。我差的是系统知识,差的结构框架和思路,所以通过视频来学习,效果更好,也更全面。关于视频学习,个人可以推荐去B站进行学习,B站上有很多学习视频,唯一的缺点就是免费的容易过时。
另外,我自己也珍藏了好几套视频资料躺在网盘里,有需要的我也可以分享给你:
2、读源码,看实战笔记,学习大神思路
“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。阅读源码,是解决问题 + 理解事物,更重要的:看到源码背后的想法;程序员说:读万行源码,行万种实践。
Spring源码深度解析:
Mybatis 3源码深度解析:
Redis学习笔记:
Spring Boot核心技术-笔记:
3、面试前夕,刷题冲刺
面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。
关于面试刷题,我个人也准备了一套系统的面试题,帮助你举一反三:
只有技术过硬,在哪儿都不愁就业,“万般带不去,唯有业随身”学习本来就不是在课堂那几年说了算,而是在人生的旅途中不间断的事情。
人生短暂,别稀里糊涂的活一辈子,不要将就。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:xhs1999xhs (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img-hamxIa4V-1713687501431)]
3、面试前夕,刷题冲刺
面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。
关于面试刷题,我个人也准备了一套系统的面试题,帮助你举一反三:
[外链图片转存中…(img-MVCykfYP-1713687501431)]
只有技术过硬,在哪儿都不愁就业,“万般带不去,唯有业随身”学习本来就不是在课堂那几年说了算,而是在人生的旅途中不间断的事情。
人生短暂,别稀里糊涂的活一辈子,不要将就。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:xhs1999xhs (备注Java)
[外链图片转存中…(img-nIu5HzWJ-1713687501432)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!