今日力扣刷题
最小覆盖子串最终实现的方案还是滑动窗口,比较特殊的是,并非所有位置都进行尝试,先固定后面的指针,当前的指针滑动到满足条件后再滑动后面的直到不满足条件,再滑动前面的,直到满足条件。
单词搜索就是一个非常简单的多起点DFS问题。唯一需要注意的是要记得记录状态的数组一定要恢复回之前的状态。
76最小覆盖子串
class Solution {
Map<Character, Integer> ori = new HashMap<Character, Integer>();
Map<Character, Integer> cnt = new HashMap<Character, Integer>();
public String minWindow(String s, String t) {
int tLen = t.length();
for (int i = 0; i < tLen; i++) {
char c = t.charAt(i);
ori.put(c, ori.getOrDefault(c, 0) + 1);
}
int l = 0, r = -1;
int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;
int sLen = s.length();
while (r < sLen) {
++r;
if (r < sLen && ori.containsKey(s.charAt(r))) {
cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
}
while (check() && l <= r) {
if (r - l + 1 < len) {
len = r - l + 1;
ansL = l;
ansR = l + len;
}
if (ori.containsKey(s.charAt(l))) {
cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);
}
++l;
}
}
return ansL == -1 ? "" : s.substring(ansL, ansR);
}
public boolean check() {
Iterator iter = ori.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Character key = (Character) entry.getKey();
Integer val = (Integer) entry.getValue();
if (cnt.getOrDefault(key, 0) < val) {
return false;
}
}
return true;
}
}
class Solution {
public boolean exist(char[][] board, String word) {
//深搜
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
boolean[][] bool = new boolean[board.length][board[0].length];
if(board[i][j] == word.charAt(0)){
bool[i][j] = true;
boolean dfs = dfs(board, word, bool, i, j, 1);
if(dfs){
return true;
}
}
}
}
return false;
}
private boolean dfs(char[][] board, String word, boolean[][] bool, int i, int j,int len) {
if(len == word.length()){
return true;
}
if(i-1 >=0 && !bool[i-1][j]&&board[i-1][j]==word.charAt(len)){
bool[i-1][j] = true;
if(dfs(board, word, bool, i-1, j, len+1)){
return true;
}
bool[i-1][j] = false;
}
if(i+1 < board.length && !bool[i+1][j]&&board[i+1][j]==word.charAt(len)){
bool[i+1][j] = true;
if(dfs(board, word, bool, i+1, j, len+1)){
return true;
}
bool[i+1][j] = false;
}
if(j-1 >=0 && !bool[i][j-1]&&board[i][j-1]==word.charAt(len)){
bool[i][j-1] = true;
if(dfs(board, word, bool, i, j-1, len+1)){
return true;
}
bool[i][j-1] = false;
}
if(j+1 < board[0].length && !bool[i][j+1]&&board[i][j+1]==word.charAt(len)){
bool[i][j+1] = true;
if(dfs(board, word, bool, i, j+1, len+1)){
return true;
}
bool[i][j+1] = false;
}
return false;
}
}
今日SpringIOC复习
Spring实现IOC/DI的方式共有三种,基于XML,基于注解方式管理Bean,基于配置类方式管理bean。
第三种是完全面向注解开发,使用的IOC容器为:
4.3.1 Bean 注解标记和扫描(loC)
需要注意的是如果不使用配置类进行扫描,那么仍然需要xml文件进行扫描
内部可以用value指定bean名字
4.3.2组件 (Bean) 作用域和周期方法注解
周期方法可以使用:@PostConstruct 制定初始化方法。@PreDestroy指定销毁方法
作用域:作用域注解需要放在Bean上
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) //单例,默认值
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //多例 二选一
4.3.3 Bean 属性赋值: 引用类型自动装配 (DI)
两个注解:@Autowired和@Resource二选一,@Resource是java的规范,然后spring实现的注解其等于@Autowired+@Qualifier(value=‘test’) value用于多个bean对象时,具体哪个进行导入。
4.3.4 Bean 属性赋值: 基本类型属性赋值 (DI)
@Value 通常用于注入外部化属性,一般用于配置文件的值的DI
如: @Value(“${catalog:hahaha}”) 其也可以用在参数的位置
4.3.5 基于注解 +XML 方式整合三层架构组件
使用这种方式创建IOC容器时,需要创建ClassPathXmlApplicationContext容器,并指定xml文件
4.4.1 完全注解开发理解
下面的三个注解都加到配置类上,在springboot中应该是加到了启动类上
@Configuration指定一个类为配置类,可以添加配置注解,替代配置xml文件
@ComponentScan(basePackages = {“包”,“包”}) 替代<context:component-scan标签实现注解扫描
@PropertySource(“classpath:配置文件地址”) 替代 <context:property-placeholder标签
4.4.2 实验一:配置类和扫描注解
@Configuration内可以使用@Bean注解声明bean对象,这种方式一般用于引入第三方框架的bean对象。
下面两个注解用于指定初始化与销毁执行的方法,具体方法还是实现在具体的bean对象的类中
@Bean(initMethod = “init”)
@Bean(destroyMethod = “cleanup”)
作用域:与@bean注解配合使用@Scope(“prototype”)
4.4.3 @Bean 定义组件与 @Bean 注解细节
先用@value引入配置文件中的值,在使用@bean和@Configuration转化为组件bean对象
bean对象之间可以通过参数的方式进行DI注入
@Bean
public HappyMachine happyMachine(){
return new HappyMachine();
}
@Bean
public HappyComponent happyComponent(HappyMachine happyMachine){
HappyComponent happyComponent = new HappyComponent();
//赋值
happyComponent.setHappyMachine(happyMachine);
return happyComponent;
}
4.4.4 实验四: 高级特性: @lmport 扩展
就是在声明IOC容器时需要指定配置类,这太多了,可以在某个配置类上通过@lmport 来导入其他配置类,成为一个总的配置类,这样最后在创建IOC容器时只需要导入一个配置类就可以了。
4.4.5 实验五: 基于注解 + 配置类方式整合三层架构组件
AnnotationConfigApplicationContext
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
4.5三种配置方式总结
XML方式配置总结
- 所有内容写到xml格式配置文件中
- 声明bean通过<bean标签
- <bean标签包含基本信息(id,class)和属性信息 <property name value / ref
- 引入外部的properties文件可以通过<context:property-placeholder
- IoC具体容器实现选择ClassPathXmlApplicationContext对象
XML+注解方式配置总结 - 注解负责标记IoC的类和进行属性装配
- xml文件依然需要,需要通过<context:component-scan标签指定注解范围
- 标记IoC注解:@Component,@Service,@Controller,@Repository
- 标记DI注解:@Autowired @Qualifier @Resource @Value
- IoC具体容器实现选择ClassPathXmlApplicationContext对象
完全注解方式配置总结 - 完全注解方式指的是去掉xml文件,使用配置类 + 注解实现
- xml文件替换成使用@Configuration注解标记的类
- 标记IoC注解:@Component,@Service,@Controller,@Repository
- 标记DI注解:@Autowired @Qualifier @Resource @Value
- <context:component-scan标签指定注解范围使用@ComponentScan(basePackages = {“com.atguigu.components”})替代
- <context:property-placeholder引入外部配置文件使用@PropertySource({“classpath:application.properties”,“classpath:jdbc.properties”})替代
- <bean 标签使用@Bean注解和方法实现
- IoC具体容器实现选择AnnotationConfigApplicationContext对象
4.6 整合 Spring5-Test5 搭建测试环境
导入
<!--junit5测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>6.0.6</version>
<scope>test</scope>
</dependency>
@SpringJUnitConfig(value = {BeanConfig.class})
Spring AOP复习
5.1 场景设定和问题复现
- AOP一种区别于OOP的编程思维,用来完善和解决OOP的非核心代码冗余和不方便统一维护问题!
- 代理技术(动态代理|静态代理)是实现AOP思维编程的具体技术,但是自己使用动态代理实现代码比较繁琐!
- Spring AOP框架,基于AOP编程思维,封装动态代理技术,简化动态代理技术实现的框架!SpringAOP内部帮助我们实现动态代理,我们只需写少量的配置,指定生效范围即可,即可完成面向切面思维编程的实现!
5.2 解决技术代理模式
被代理是核心代码,其套通了代理的非核心逻辑代码
静态代理:需要对每个类每个方法进行代码撰写(繁琐!!!)
动态代理:
jdk要求有接口
cjlib不要求有接口
aop实际就是对动态代理的简化!!!
场景:
1.日志记录
2.事务处理
3.性能监控
4.异常处理
5.3 面向切面编程思维 (AOP)
核心名词:
1.横切关注点:与核心关注点相对,指的是与核心代码无关的关注点
2.增强:每一个关注点都要写一个方法,增强有五种1.前置2返回3异常4后置finally5环绕
3连接点:能切的方法
4切入点:真正切的点(被选的连接点)
5切面:连接点加切入点(切入点+增强)
6织入:增强这个动作
7代理:被切入的类
8目标:要被切入的类
5.5 Spring AOP 基于注解方式实现和细节
实现的底层技术:如果代理类有接口则通过JDK方式实现,且只能通过接口获取bean,因为放入IOC容器中的是代理类。如果没有接口,则通过cjlib方式实现,可以通过类来获取bean
具体的实现注解:@Aspect@Conponent@其他放在方法上的注解
// @Aspect表示这个类是一个切面类
@Aspect
// @Component注解保证这个切面类能够放入IOC容器
@Component
public class LogAspect {
// @Before注解:声明当前方法是前置通知方法
// value属性:指定切入点表达式,由切入点表达式控制当前通知方法要作用在哪一个目标方法上
@Before(value = "execution(public int com.atguigu.proxy.CalculatorPureImpl.add(int,int))")
public void printLogBeforeCore() {
System.out.println("[AOP前置通知] 方法开始了");
}
@AfterReturning(value = "execution(public int com.atguigu.proxy.CalculatorPureImpl.add(int,int))")
public void printLogAfterSuccess() {
System.out.println("[AOP返回通知] 方法成功返回了");
}
@AfterThrowing(value = "execution(public int com.atguigu.proxy.CalculatorPureImpl.add(int,int))")
public void printLogAfterException() {
System.out.println("[AOP异常通知] 方法抛异常了");
}
@After(value = "execution(public int com.atguigu.proxy.CalculatorPureImpl.add(int,int))")
public void printLogFinallyEnd() {
System.out.println("[AOP后置通知] 方法最终结束了");
}
}
JoinPoint 作为上面四种的参数,可以通过反射的方式获取方法签名、传入的实参等信息
切点表达式语法
重用切点表示可以通过下面的方式在某一个方法上指定,后
@Before(value = “declarPointCut()”)
@Pointcut(“execution(public int com.atguigu.aop.api.Calculator.add(int,int)))”)
public void declarPointCut() {}
也可以统一放在一个类中,但是此类也需要时bean对象
环绕通知@Around :1.其传入的是ProceedingJoinPoint ,2.其次其更像动态代理方式,可以多方面插入 3.其需要返回返回值和放入参数
.// 使用@Around注解标明环绕通知方法
@Around(value = "com.atguigu.aop.aspect.AtguiguPointCut.transactionPointCut()")
public Object manageTransaction(
// 通过在通知方法形参位置声明ProceedingJoinPoint类型的形参,
// Spring会将这个类型的对象传给我们
ProceedingJoinPoint joinPoint) {
// 通过ProceedingJoinPoint对象获取外界调用目标方法时传入的实参数组
Object[] args = joinPoint.getArgs();
// 通过ProceedingJoinPoint对象获取目标方法的签名对象
Signature signature = joinPoint.getSignature();
// 通过签名对象获取目标方法的方法名
String methodName = signature.getName();
// 声明变量用来存储目标方法的返回值
Object targetMethodReturnValue = null;
try {
// 在目标方法执行前:开启事务(模拟)
log.debug("[AOP 环绕通知] 开启事务,方法名:" + methodName + ",参数列表:" + Arrays.asList(args));
// 过ProceedingJoinPoint对象调用目标方法
// 目标方法的返回值一定要返回给外界调用者
targetMethodReturnValue = joinPoint.proceed(args);
// 在目标方法成功返回后:提交事务(模拟)
log.debug("[AOP 环绕通知] 提交事务,方法名:" + methodName + ",方法返回值:" + targetMethodReturnValue);
}catch (Throwable e){
// 在目标方法抛异常后:回滚事务(模拟)
log.debug("[AOP 环绕通知] 回滚事务,方法名:" + methodName + ",异常:" + e.getClass().getName());
}finally {
// 在目标方法最终结束后:释放数据库连接
log.debug("[AOP 环绕通知] 释放数据库连接,方法名:" + methodName);
}
return targetMethodReturnValue;
}
切面的优先级@Order放在切面类上