重试框架入门:Spring-RetryGuava-Retry
前言
在日常工作中,随着业务日渐庞大,不可避免的涉及到调用远程服务,但是远程服务的健壮性和网络稳定性都是不可控因素,因此,我们需要考虑合适的重试机制去处理这些问题,最基础的方式就是手动重试,侵入业务代码去处理,再高端一点的通过切面去处理,较为优雅的实现重试,下面,介绍两个重试框架,只需要配置好重启策略及重试任务,即可使用。
重试任务
这里只是模拟传参、相应及异常,具体任务需对应业务
package com.example.test.MessageRetry;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.remoting.RemoteAccessException;@Slf4j
public class RetryTask {/*** 重试方法* @param param* @return*/public static boolean retryTask(String param){log.info("请求参数:{}",param);int i = RandomUtils.nextInt(0,15);log.info("随机数:{}",i);if(i == 0){log.error("参数异常");throw new IllegalArgumentException("参数异常");}else if(i > 10){log.error("访问异常");throw new RemoteAccessException("访问异常");}else if(i % 2 == 0){log.info("成功");return true;}else{log.info("失败");return false;}}
}
Spring-Retry
简介
Spirng-Retry是Spring提供的一个重试框架,为spring程序提供声明式重试支持,主要针对可能抛出异常的调用操作,进行有策略的重试。可以通过代码方式和注解方式实现,主要由重试执行者和两个策略构成:
- RetryTemplet:重试执行者,可以设置重试策略(设置重试上线、如何重试)和回退策略(立即重试还是等待一段时间后重试,默认立即重试,如果需要配置等待一段时间后重试则需要指定回退策略),通过Execute提交执行操作,只有在调用时抛出指定配置的异常,才会执行重试
- 重试策略:
| 策略 | 方式 |
|---|---|
| NeverRetryPolicy | 只允许调用RetryCallback一次,不允许重试 |
| AlwaysRetryPolicy | 允许无限重试,直到成功,此方式逻辑不当会导致死循环 |
| SimpleRetryPolicy | 固定次数重试策略,默认重试最大次数为3次,RetryTemplate默认使用的策略 |
| TimeoutRetryPolicy | 超时时间重试策略,默认超时时间为1秒,在指定的超时时间内允许重试 |
| ExceptionClassifierRetryPolicy | 设置不同异常的重试策略,类似组合重试策略,区别在于这里只区分不同异常的重试 |
| CircuitBreakerRetryPolicy | 有熔断功能的重试策略,需设置3个参数openTimeout、resetTimeout和delegate |
| CompositeRetryPolicy | 组合重试策略,有两种组合方式,乐观组合重试策略是指只要有一个策略允许即可以重试,悲观组合重试策略是指只要有一个策略不允许即可以重试,但不管哪种组合方式,组合中的每一个策略都会执行 |
- 重试回退策略:
| 回退策略 | 方式 |
|---|---|
| NoBackOffPolicy | 无退避算法策略,每次重试时立即重试 |
| FixedBackOffPolicy | 固定时间的退避策略,需设置参数sleeper和backOffPeriod,sleeper指定等待策略,默认是Thread.sleep,即线程休眠,backOffPeriod指定休眠时间,默认1秒 |
| UniformRandomBackOffPolicy | 随机时间退避策略,需设置sleeper、minBackOffPeriod和maxBackOffPeriod,该策略在minBackOffPeriod,maxBackOffPeriod之间取一个随机休眠时间,minBackOffPeriod默认500毫秒,maxBackOffPeriod默认1500毫秒 |
| ExponentialBackOffPolicy | 指数退避策略,需设置参数sleeper、initialInterval、maxInterval和multiplier,initialInterval指定初始休眠时间,默认100毫秒,maxInterval指定最大休眠时间,默认30秒,multiplier指定乘数,即下一次休眠时间为当前休眠时间*multiplier |
| ExponentialRandomBackOffPolicy | 随机指数退避策略,引入随机乘数可以实现随机乘数回退 |
- 此外,还需要配置重试时间间隔、最大重试次数以及可重试异常
实现
代码方式
RetryTemplate通过execute提交执行操作,需要准备RetryCallback和RecoveryCallback两个类实例,前者对应的就是重试回调逻辑实例,包装正常的功能操作,RecoveryCallback实现的是整个执行操作结束的恢复操作实例,只有在调用的时候抛出了异常,并且异常是在exceptionMap中配置的异常,才会执行重试操作,否则就调用到excute方法的第二个执行方法RecoveryCallback中
package com.example.test.MessageRetry;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;@Service
@Slf4j
public class SpringRetryService {/*** 重试时间间隔ms,默认1000ms*/private long retryPeriodTime = 5000L;/*** 最大重试次数*/private int maxRetryNum = 3;/*** 哪些结果和异常要重试,key表示异常类型,value表示是否需要重试*/private Map<Class<? extends Throwable>,Boolean> retryMap = new HashMap<>();@Testpublic void test(){retryMap.put(IllegalArgumentException.class,true);retryMap.put(RemoteAccessException.class,true);//构建重试模板RetryTemplate retryTemplate = new RetryTemplate();//设置重试回退操作策略,主要设置重试时间间隔FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();backOffPolicy.setBackOffPeriod(retryPeriodTime);//设置重试策略,主要设置重试次数SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryNum,retryMap);retryTemplate.setRetryPolicy(retryPolicy);retryTemplate.setBackOffPolicy(backOffPolicy);Boolean execute = retryTemplate.execute(//RetryCallbackretryContext -> {boolean b = RetryTask.retryTask("aaa");log.info("调用结果:{}",b);return b;},retryContext -> {//RecoveryCallbacklog.info("到达最多尝试次数");return false;});log.info("执行结果:{}",execute);}
}

注解方式
上面我们说到Spring-Retry是Spring提供的,那么,它就支持依赖整合
<!--spring-retry--><dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId><version>1.2.2.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.1</version></dependency>
然后,在启动类上添加开启注解
//表示是否开启重试,属性proxyTargetClass,boolean类型,是否创建基于子类(CGLIB)的代理,而不是标准的基于接口的代理,默认false
@EnableRetry
package com.example.test.MessageRetry;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.remoting.RemoteAccessException;@Slf4j
public class RetryTask {/*** 重试方法* @param param* @return*/public static boolean retryTask(String param){log.info("请求参数:{}",param);int i = RandomUtils.nextInt(0,15);log.info("随机数:{}",i);if(i >-1){log.error("参数异常");throw new IllegalArgumentException("参数异常");
// }else if(i > 10){
// log.error("访问异常");
// throw new RemoteAccessException("访问异常");
// }else if(i % 2 == 0){
// log.info("成功");
// return true;}else{log.info("失败");return false;}}
}
/*** 重试调用方法* @param param* @return* @Retryable注解:**/@Retryable(value = {RemoteAccessException.class,IllegalArgumentException.class},maxAttempts = 3,backoff = @Backoff(delay = 5000L,multiplier = 2))public void call(String param){RetryTask.retryTask(param);}/*** 达到最大重试次数,或抛出了没有指定的异常* @param e* @param param* @return*/@Recoverpublic void recover(Exception e,String param){log.error("达到最大重试次数!!!!!");}
@Testpublic void retry(){springRetryService.call("aaa");}
- @Retryable注解说明
| 属性 | 说明 |
|---|---|
| value | 指定重试的异常类型,默认为空 |
| maxAttempts | 最大尝试次数,默认3次 |
| include | 和value一样,默认为空,当exclude也为空时,默认所有异常 |
| exclude | 指定不处理的异常 |
| Backoff | 重试策略 |
- @Backoff注解说明:设定重试倍数,每次重试时间是上次的n倍
| 属性 | 说明 |
|---|---|
| delay | 重试之间的等待时间(以毫秒为单位),默认0 |
| maxDelay | 重试之间的最大等待时间(以毫秒为单位),默认0 |
| multiplier | 延迟的倍数,默认0.0 |
| delayExpression | 重试之间的等待时间表达式,默认空 |
| maxDelayExpression | 重试之间的最大等待时间表达式,默认空 |
| multiplierExpression | 指定延迟的倍数表达式,默认空 |
| random | 随机指定延迟时间,默认false |
-
@Recover注解说明:当重试到达指定次数时,将要回调的方法
-
@Retryable和@Recover修饰的方法要在同一个类中,且被@Retryable和@Recover标记的方法不能有返回值,这样Recover方法才会生效。由于@Retryable注解是通过切面实现的,因此我们要避免@Retryable 注解的方法的调用方和被调用方处于同一个类中,因为这样会使@Retryable 注解失效。

我们可以看到,Spring-Retry只能针对指定异常重试,不能根据执行结果返回值重试,整体使用也比较死板,下面,看下更加灵活的Guava-Retry。
Guava-Retry
简介
Guava-Retry是谷歌的Guava库的一个小扩展,允许为任意函数调用创建可配置的重试策略,我们可以通过构建重试实例RetryBuilder,来设置重试源、配置重试次数、重试超时时间、等待时间间隔等,实现优雅的重试机制。
- 主要属性
| 属性 | 说明 |
|---|---|
| attemptTimeLimiter | 时间限制策略,单次任务执行时间限制,超时终止 |
| stopStrategy | 停止重试策略 |
| waitStrategy | 等待策略 |
| blockStrategy | 任务阻塞策略,即当前任务执行完,下次任务执行前做什么,仅有线程阻塞threadSleepStrategy |
| retryException | 重试异常(重试策略) |
| listeners | 自定义重试监听器,可用于记录日志等 |
- 时间限制策略
| 策略 | 说明 |
|---|---|
| NoAttemptTimeLimit | 对代理方法不添加时间限制,默认 |
| FixedAttemptTimeLimit | 对代理方法的尝试添加固定时间限制 |
- 重试策略(重试异常)
| 策略 | 说明 |
|---|---|
| retryIfException | 抛出 runtime 异常、checked 异常时都会重试,但是抛出 error 不会重试 |
| retryIfRuntimeException | 只会在抛 runtime 异常的时候才重试,checked 异常和error 都不重试 |
| retryIfExceptionOfType | 允许我们只在发生特定异常的时候才重试,比如NullPointerException 和 IllegalStateException 都属于 runtime 异常,也包括自定义的error |
| retryIfResult | 可以指定你的 Callable 方法在返回值的时候进行重试 |
- 停止策略
| 策略 | 说明 |
|---|---|
| StopAfterDelayStrategy | 设定最长执行时间,无论任务执行几次,一旦超时,任务终止,返回RetryException |
| StopAfterAttemptStrategy | 设定最大尝试次数,一旦超过,返回重试异常 |
| NeverStopStrategy | 一直轮询直到获取期望结果 |
- 等待策略
| 策略 | 说明 |
|---|---|
| ExceptionWaitStrategy | 异常时长等待,如果抛出的是指定异常,则从传入的方法中取得等待时间并返回;如果异常不匹配,则返回等待时间为0L |
| CompositeWaitStrategy | 复合时长等待,在获取等待时间时会获取多种等待策略各自的等待时间,然后累加这些等待时间 |
| FibonacciWaitStrategy | 斐波那契等待策略 |
| ExponentialWaitStrategy | 指数等待时长,指数增长,若设置了最大时间,则停止,否则到Long.MAX_VALUE |
| IncrementingWaitStrategy | 递增等待,提供一个初始时长和步长,随次数叠加 |
| RandomWaitStrategy | 随机等待时长,可以提供一个最大和最小时间,从范围内随机 |
| FixedWaitStrategy | 固定等待时长 |
代码
<!--guava-retryer--><dependency><groupId>com.github.rholder</groupId><artifactId>guava-retrying</artifactId><version>2.0.0</version></dependency>
package com.example.test.MessageRetry;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.remoting.RemoteAccessException;@Slf4j
public class RetryTask {/*** 重试方法* @param param* @return*/public static boolean retryTask(String param){log.info("请求参数:{}",param);int i = RandomUtils.nextInt(0,15);log.info("随机数:{}",i);if(i < 3){log.error("参数异常");throw new IllegalArgumentException("参数异常");}else if(i > 10){log.error("访问异常");throw new RemoteAccessException("访问异常");}else if(i % 2 == 0){log.info("成功");return true;}else{log.info("失败");return false;}}
}
package com.example.test.MessageRetry;import com.github.rholder.retry.*;
import com.google.common.base.Predicates;
import lombok.extern.slf4j.Slf4j;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
@Slf4j
public class GuavaRetryService {public void guavaRetry(){//构建重试实例RetryBuilder,可以设置重试源,可以配置重试次数、重试超时时间、等待时间间隔Retryer<Boolean>retryer = RetryerBuilder.<Boolean>newBuilder()//设置异常重试源.retryIfExceptionOfType(RemoteAccessException.class).retryIfExceptionOfType(IllegalArgumentException.class)//设置根据结果重试 res->res==false Predicates.containsPattern("_error$").retryIfResult(Predicates.equalTo(false))//设置等待时间.withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))//设置最大重试次数.withStopStrategy(StopStrategies.stopAfterAttempt(3))//设置重试监听,可用作重试时的额外动作.withRetryListener(new RetryListener() {@Overridepublic <V> void onRetry(Attempt<V> attempt) {log.error("第【{}】次调用失败",attempt.getAttemptNumber());}})//设置阻塞策略.withBlockStrategy(BlockStrategies.threadSleepStrategy())//设置时间限制.withAttemptTimeLimiter(AttemptTimeLimiters.noTimeLimit()).build();try{retryer.call(()->RetryTask.retryTask("aaa"));}catch (Exception e){e.printStackTrace();}}
}

可以看到,我们设置了重试三次,超过这个限制没有执行成功,抛出了重试异常,而且也可以根据我们的返回结果来判断。
总结
Spring-Retry和Guava-Retry都是线程安全的重试框架,能够保证并发业务下重试逻辑的正确性。两者都很好的将正常方法和重试方法进行了解耦,可以设置超时时间、重试次数、间隔时间、监听结果等,相比来说,Guava-Retry比Spring-Retry更加灵活,并且可以通过返回值来进行重试,两者都是非常好的重试框架,具体的选用看相关的业务场景即可。
相关文章:
重试框架入门:Spring-RetryGuava-Retry
前言 在日常工作中,随着业务日渐庞大,不可避免的涉及到调用远程服务,但是远程服务的健壮性和网络稳定性都是不可控因素,因此,我们需要考虑合适的重试机制去处理这些问题,最基础的方式就是手动重试…...
[QCM6125][Android13] 修复PRODUCT_COPY_FILES无法拷贝so
文章目录 开发平台基本信息问题描述解决方法 开发平台基本信息 芯片: QCM6125 版本: Android 13 kernel: msm-4.14 问题描述 在进行系统移植时,经常会把一些自己开发的c或者c程序编译成so库,然后在系统服务中去调用这些库。所以在进行新代码开发时&am…...
微服务Eureka注册中心
目录 一、Eureka的结构和作用 二、搭建eureka-server 三、服务注册 四、服务发现 假如我们的服务提供者user-service部署了多个实例,如图: 存在的问题: order-service在发起远程调用的时候,该如何得知user-service实例的ip地址…...
Java:企业级java后端开发,需要掌握哪些内容
一、什么是后端开发 后端开发是指开发基于服务器端的软件应用程序,也称为系统的后台或服务器端编程。 后端程序员负责处理网站或应用程序后台的逻辑和功能,包括数据库管理、服务器端脚本编写、API设计、数据安全性、网站性能优化等。 后端开发技术通常包…...
使用Go语言生成Excel任务表依赖图(Markdown文件mermaid图)
一、前言 在游戏中,任务是非常常见的玩法,可能会有主线任务,支线任务以及其它一些类型的任务,各任务可能还会有前置任务,即需要完成某个任务之后,才能做当前任务。在游戏开发中,配置表可以使用…...
C语言和C++的区别在哪?如何自学C++?
C语言和C是两种不同的编程语言,它们在语法、特性和用途上有一些区别。以下是C语言和C的一些主要区别: 面向对象编程:C是一种支持面向对象编程的语言,它在C语言的基础上添加了类、对象、继承、多态等面向对象的特性。而C语言是一种…...
功能强大的开源数据中台系统 DataCap 1.13.0 发布
推荐一套基于 SpringBoot 开发的简单、易用的开源权限管理平台,建议下载使用: https://github.com/devlive-community/authx 推荐一套为 Java 开发人员提供方便易用的 SDK 来与 OpenAI 的 API 进行交互组件:https://github.com/devlive-community/openai…...
JTS Self-intersection异常TopologyException: side location conflict解决办法
JTS Self-intersection异常TopologyException: side location conflict解决办法 举例:问题围栏 MULTIPOLYGON (((114.0905685 32.1120567, 114.0905685 32.112957, 114.0905685 32.1138535, 114.0905685 32.1147537, 114.0905685 32.115654, 114.0905685 32.11655…...
Maven: No compiler is provided in this environment.
在Eclipse中运行Maven项目,报错: No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK? 解决方法: Windows > Preferences > Java > Installed JREs > Add > Standard VM,…...
.NET-10. 其他-VSTO+VBA
VSTOVBA 前言VSTO 外接程序介绍:VSTO参考链接:VSTO 例子: VBA:参考链接: 前言 主要用于Excel插件。 VSTO 外接程序介绍: Excel、Word、PowerPoint、Project、Visio等等Office应用程序 相对简单 VSTO参考链接&#x…...
相机传感器格式与镜头光圈参数
相机靶面大小 CCD/CMOS图像传感器尺寸(sensor format)1/2’‘、1/3’‘、1/4’实际是多大 1英寸——靶面尺寸为宽12.7mm*高9.6mm,对角线16mm。 2/3英寸——靶面尺寸为宽8.8mm*高6.6mm,对角线11mm。 1/2英寸——靶面尺寸为宽6.…...
Android 设置头像(拍照获取、相册获取、裁剪照片)
在Android原生态开发过程中,往往会设计到用户头像的设置问题,一般来讲设置头像需要用到拍照、获取照片、存储照片、裁剪照片、显示照片等问题,本文将一步一步的进行说明讲解。 首先需要强调几点我在开发过程中遇到的问题。 权限问题…...
android开发之Android 自定义滑动解锁View
自定义滑动解锁View 需求如下: 近期需要做一个类似屏幕滑动解锁的功能,右划开始,左划暂停。 需求效果图如下 实现效果展示 自定义view如下 /** Desc 自定义滑动解锁View Author ZY Mail sunnyfor98gmail.com Date 2021/5/17 11:52 *…...
CAD绘制法兰、添加光源、材质并渲染
首先绘制两个圆柱体,相互嵌套 在顶部继续绘制圆柱体,这是之后要挖掉的部分 在中央位置绘制正方形 用圆角工具: 将矩形的四个角分别处理,效果: 用拉伸工具 向上拉伸到和之前绘制的圆柱体高度齐平 绘制一个圆柱体&#…...
ChatGPT访问流量下降的原因分析
自从OpenAI的ChatGPT于11月问世以来,这款聪明的人工智能聊天机器人就席卷了全世界,人们在试用该工具的同时也好奇该技术到底将如何改变我们的工作和生活。 但近期Similarweb表示,自去ChatGPT上线以来,该网站的访问量首次出现下…...
干货 | 详述 Elasticsearch 向量检索发展史
1. 引言 向量检索已经成为现代搜索和推荐系统的核心组件。 通过将复杂的对象(例如文本、图像或声音)转换为数值向量,并在多维空间中进行相似性搜索,它能够实现高效的查询匹配和推荐。 图片来自:向量数据库技术鉴赏【上…...
mysql常见面试题,高频题目放送
互联网的产品架构是包含这接入层,逻辑处理以及储存层的,其中储存层承载着较多的数据以及持久化的任务,而说到储存层,避免不了说到数据库,在我们面试的时候,数据库的知识题目占比是非常多的: 1.…...
使用 PowerShell 将 Excel 中的每个工作表单独另存为独立的文件
导语:在日常工作中,我们经常需要处理 Excel 文件。本文介绍了如何使用 PowerShell 脚本将一个 Excel 文件中的每个工作表单独另存为独立的 Excel 文件,以提高工作效率。 1. 准备工作 在开始之前,请确保已经安装了 Microsoft Exc…...
python提取pdf图片
import fitz import re import osdef save_pdf_img(path, save_path):path: pdf的路径save_path : 图片存储的路径# 使用正则表达式来查找图片checkXO r"/Type(? */XObject)"checkIM r"/Subtype(? */Image)"# 打开pdfdoc fitz.open(path)# 图片计数im…...
Vue3 表单输入绑定简单应用
去官网学习→表单输入绑定 | Vue.js 运行示例: 代码:HelloWorld.vue <template><div class"hello"><h1>Vue 表单输入绑定</h1><input type"text" placeholder"输入框" v-model"msg"…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
算法打卡第18天
从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 示例 1: 输入:inorder [9,3,15,20,7…...
