每日总结 Day3 (不知道能坚持多久)
力扣9:55-12:25
2661. 找出叠涂元素 中等
- 一开始想到的就是一个暴力求解 好不疑问地超时了因为我这样每次都需要去遍历整个二维数组去找对应地值
- 时间复杂度 n*n
- 还有一点可以优化地就是不需要去初始化hang和lie数组比较条件直接换成他们地值是否等于m和n即可
public int firstCompleteIndex(int[] arr, int[][] mat) {
int[] hang = new int[mat.length];
for (int i = 0; i < mat.length; i++) {
hang[i] = mat[0].length;
}
int[] lie = new int[mat[0].length];
for (int i = 0; i < mat[0].length; i++) {
lie[i] = mat.length;
}
for (int q = 0; q < arr.length; q++) {
for (int i = 0; i < mat.length; i++) {
int flag = 0;
for (int j = 0; j < mat[0].length; j++) {
if (mat[i][j] == arr[q]) {
hang[i]--;
if (hang[i] == 0) return q;
lie[j]--;
if (lie[j] == 0) return q;
flag = 1;
break;
}
}
if (flag == 1) break;
}
}
return 0;
}
- 看了题解后的做法
- 用一个map来进行存储每个值与其对应地i j地值,这样就只需要便利一次二维数组就能把所有地二维数组里面的值和下标信息进行储存
- 然后遍历arr数组用map.get获取到这个数字在矩阵中对应的下标
- 时间复杂度:n
public int firstCompleteIndex(int[] arr, int[][] mat) {
int m = mat.length, n = mat[0].length;
HashMap<Integer, int[]> map = new HashMap<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
map.put(mat[i][j], new int[]{i, j});
}
}
int[] row = new int[m];
int[] col = new int[n];
int res = 0;
for (int i = 0; i < arr.length; i++) {
int[] nums = map.get(arr[i]);
row[nums[0]]++;
col[nums[1]]++;
if (row[nums[0]] == n || col[nums[1]] == m) {
res = i;
break;
}
}
return res;
}
188. 买卖股票的最佳时机 IV 困难
- 第一次自己写出来的困难题
- 总体思路和III其实差不多,就是每次买股票都有两个状态,i次买入和i次卖出,在加定义一个初始的值,这样便利的时候不用额外写情况考虑。
- 时间复杂度n*2K
public int maxProfit(int k, int[] prices) {
//dp[i][j] j表示为奇数字次数的时候是买入状态
int[][] dp = new int[prices.length][k * 2 + 1];
for (int i = 1; i <= k * 2; i++) {
if (i % 2 == 1) dp[0][i] = -prices[0];
}
for (int i = 1; i < prices.length; i++) {
for (int j = 1; j <= 2 * k; j++) {
// //第一次持有
// dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
// //第一次卖出
// dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
//
//推导递推
//买入
if (j % 2 == 1) dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] - prices[i]);
//卖出
else dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + prices[i]);
}
}
return dp[prices.length - 1][2 * k];
}
309. 买卖股票的最佳时机含冷冻期 中等
- 没写出来,一开始做的时候想的是定义三个状态:持有、不持有、冷冻,然后写递推公式的时候就发现写不出来了
- 正确思路:定义四个状态:持有、保持卖出、今天卖出、冷冻
- 这样状态一定义,思路就很清晰了
public static int maxProfit(int[] prices) {
int[][] dp = new int[prices.length][4];
//0 表示持有
dp[0][0] = -prices[0];
//1 表示保持卖出的状态
//2 表示今天卖出
//3 表示冷冻
System.out.println(dp[0][0] + " " + dp[0][1] + " " + dp[0][2] + " " + dp[0][3]);
for (int i = 1; i < prices.length; i++) {
//2 表示保持卖出股票的状态 保持前一天的状态或者前一天冷冻
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][3]);
//0 表示持有 前一天就持有 前一天正在冷冻或者前一天就保持卖出的状态
dp[i][0] = Math.max(dp[i - 1][0], Math.max(dp[i - 1][3], dp[i - 1][2]) - prices[i]);
//1 表示今天卖出
dp[i][1] = dp[i - 1][0] + prices[i];
//3 表示冷冻
dp[i][3] = dp[i - 1][1];
System.out.println(dp[i][0] + " " + dp[i][1] + " " + dp[i][2] + " " + dp[i][3]);
}
//持有股票的状态肯定不是最高利润的时候,所以剩下三个状态取最大值
return Math.max(dp[prices.length - 1][3], Math.max(dp[prices.length - 1][1], dp[prices.length - 1][2]));
}
714. 买卖股票的最佳时机含手续费 中等
- 和II没有什么差别 就多减去一个手续费就好了
public int maxProfit(int[] prices, int fee) {
int[][] dp = new int[prices.length][2];
//0持有股票
dp[0][0] = -prices[0] - fee;
//1卖出股票
dp[0][1] = 0;
for (int i = 1; i < prices.length; i++) {
//0持有股票
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i] - fee);
//1卖出股票
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
}
return dp[prices.length - 1][1];
}
ok下班,吃饭去了
设计模式 14:10-17:25
里氏替换原则
在面向对象中继承带来的问题
- 继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有 的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。
- 继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低, 增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且 父类修改后,所有涉及到子类的功能都有可能产生故障
- 问题提出:在编程中,如何正确的使用继承? => 里氏替换原则
概念:该原则的核心思想就是在程序当中,如果将一个父类对象替换成它的子类对象后,该程序不会发生异常。这也是该原则希望达到的一种理想状态。通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。在适当的情况下,可以通过组合聚合依赖的方式来解决问题。
- 当父类和子类都有相同特点时候可以进行一个抽象,抽象一个基类。
开闭原则OCP
- 一个软件如是一个类,对扩展开放(开发者),对修改关闭(使用方)。即在拓展增加功能的时候不能改变原来的代码,不会对原来的业务进行影响-
迪米特法则
基本介绍
- 一个对象应该对其他对象保持最少的了解
- 类与类关系越密切,耦合度越大
- 迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于 被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的 public 方法,不对外泄露任何信息
- 迪米特法则还有个更简单的定义:只与直接的朋友通信
- 直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间 是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变 量的形式出现在类的内部
注意事项
- 迪米特法则的核心是降低类的耦合
- 但是注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低类间(对象间)耦合关系, 并不是 要求完全没有依赖关系
合成复用原则
类与类之间尽量不适用继承的方式,使用组合(就是A a= new A() 直接将所需的类作为成员变量引入,不可分离)、聚合(A a;,然后有个set设对a进行设置,也可以设置为空,所以可以分离)、依赖(在方法的参数进行传递)的方式进行
设计的核心思想
- 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
- 针对接口编程,而不是针对实现编程。
- 为了交互对象之间的松耦合设计而努力
UML类图
依赖
在A类中如果用到了B类,那么就是A类依赖B类,如果没有B类,A类就不能整除运行
- 是类的成员变量
- 是类中方法的返回类型
- 是类中方法的参数
- 在类中方法里面使用到了
- PseronServiceBean依赖于下面这些类
泛化
实际上就是继承关系,他是依赖关系中的一个特例
- PersonService 继承 了DaoSupport
实现
就是实现接口
- PersonServiceBean实现了PersonService
关联关系
类与类之间的联系
聚合
表示整体与部分的关系,整体和部分能够分开。聚合关系是关联关系的一中特例,因此他也具有导航型和多重性。
- Computer聚合Mouse和Moniter
组合
组合也是表示整体和部分的关系,但是和聚合的区别就是整体与部分不能分离!!
Person 组合Head Person聚合IDCard
实习僧投递 19:00-20:00
昨天都打算不投了,因为我感觉自己的知识储备不是很够,很多东西都不会,还有点畏惧面试,怕一紧张脑子就空了。今天看了鱼总第一段的实习经历给了我挺大的勇气的,不会就不会,问到了也没啥,大不了就换下一家所以还是投下试试吧
面试题以及知识复习 20:-21:40
反射
Java反射(超详细!)_一个快乐的野指针~的博客-CSDN博客
String 、StringBuilder、StringBuffer
- Sting 是一个不可变的对象,一但被创建,就不能更改
- StringBuffer和StringBuilder都是可变的对象,其中StringBuffer是线程安全的,他的所有方法都是同步的,因此他可以同时被多个线程同时访问和修改。
- StringBuilder不具有线程安全性,,适用于单线程的字符串处理,但是他相比于StringBuffer而言性能会更加高
内部类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
总结
今天还没好完,还是有点不舒服,以至于又鸽了一天锻炼,明天一定!
明日计划
- 力扣
- 设计模式
- html前端作业完成
- 突击一下蓝桥杯校赛
- 锻炼!
睡觉睡觉
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
