leecodecode【双指针题2】【2026.5.26打卡-java版本】

盛最多水的容器

要点:right-left, 移动小的那边

java 复制代码
class Solution {
    public int maxArea(int[] height) {
        //双指针

        int left = 0;
        int right = height.length -1;
        int ans = 0;
        while(left < right){

            int area = (right - left) * Math.min(height[left], height[right]);
            ans =  Math.max(ans, area);

            if(height[left] < height[right]){
                left++;
            }else{
                right--;
            }

            
        }

        return ans;
        
    }
}

接雨水

要点: 双指针找到短的那边 ,记录leftmax, rightmax

java 复制代码
class Solution {
    public int trap(int[] height) {
        int maxleft = height[0];
        int maxright = height[height.length -1];

        int left = 1;
        int right = height.length - 2;

        int ans = 0;
        while(left <= right){
            if(maxleft < maxright){
                if(maxleft <= height[left]){
                    maxleft = height[left];
                }else{
                    ans += maxleft - height[left];
                }
                left++;
            }else{
                if(maxright <= height[right]){
                    maxright = height[right];
                }else{
                    ans += maxright - height[right];
                }
                right--;

            }
        }
        
        return ans;
    }
}

判断子序列

要点: s一个指针i, t一个指针j

java 复制代码
class Solution {
    public boolean isSubsequence(String s, String t) {
        //双指针
        int i = 0;
        int j = 0;

        while(j < t.length()  ){
            char  c = t.charAt(j);
            if(i < s.length()&& s.charAt(i) == c){
                i++;
            }
            j++;
        }

        return i == s.length();
        
    }
}

随机知识

业务

1.登录业务

(1)双token机制

token是什么?

(2)切面限流

1. 什么是 Token?为什么要用 Token?

问:你能解释一下 Token 是什么吗?与 Session 有什么区别?

答:

Token 可以理解为服务器颁发给客户端的临时凭证 ,客户端每次请求时带上它,证明"我是合法登录的用户"。它类似一张有时效、有权限的门禁卡

与 Session 的主要区别:

  • Session:服务器存储用户信息(有状态),需要共享存储(如 Redis)才能多机共用。
  • Token:客户端存储 Token(通常用 JWT),服务器只负责签发和验证(无状态),天然适合分布式系统。

2. 双 Token(Access Token + Refresh Token)的流程

问:你们项目里是怎么做登录态管理的?为什么需要双 Token?

答:

我们使用的是双 Token 方案

  • Access Token:有效期短(15分钟),用于调用业务接口(加购物车、下单等)。
  • Refresh Token :有效期长(7天),不参与业务,唯一的职责是去换取新的 Access Token。

流程:

  1. 登录成功后,服务端返回一对 Token。
  2. 客户端将 Access Token 放在请求头中调用业务接口。
  3. 若 Access Token 过期(返回 401),客户端拿 Refresh Token 调用 /refresh 接口。
  4. 服务端验证 Refresh Token 有效后,颁发新的 Access Token(有时也刷新 Refresh Token)。
  5. 客户端用新 Token 重试原来的请求。

好处:

  • 用短期 Access Token 降低泄露风险。
  • 用长期 Refresh Token 实现无感续期,提升体验。
  • 修改密码或异常时,仅吊销 Refresh Token 即可强制下线。

3. 注解和切面是如何联系上的?

问:我看到一个限流注解 @AccessLimit,但它只是一个注解,没有任何执行逻辑。请问它怎么起到限流作用的?注解和切面之间是怎么联系起来的?

答:

注解本身只是元数据 ,真正执行逻辑的是 AOP 切面 。它们的联系是通过 Spring AOP 的切入点表达式 建立的,步骤如下:

  1. 定义注解 @AccessLimit,包含 limittime 等属性。

  2. 编写切面类 AccessLimitAspect,并标注 @Aspect@Component

  3. 在切面中写一个 @Around 方法,切入点表达式为 @annotation(accessLimit)

    java

    @Around("@annotation(accessLimit)")

    public Object limit(ProceedingJoinPoint joinPoint, AccessLimit accessLimit) {

    // 读取注解参数,进行限流检查...

    }

  4. Spring 启动时,解析该表达式,自动为所有标注了 @AccessLimit 的方法创建代理对象

  5. 运行时调用该方法,会先执行切面中的限流逻辑。若通过,再通过 joinPoint.proceed() 调用原始方法;若超限则直接返回错误,原始方法不再执行。

关键点: 不是注解主动找到切面,而是切面主动声明"我要处理所有带有这个注解的方法"。没有切面,注解就是单纯的注释。


4. 双 Token 的常见追问(展示深度)

追问1:Refresh Token 存储在哪里?有什么安全要求?

Refresh Token 必须放在 HttpOnly Cookie 或移动端安全存储中,绝不能放在 localStorage,否则易被 XSS 窃取。Access Token 可以放在内存或短时 Cookie 中。

追问2:如果 Refresh Token 也被偷了怎么办?

可以使用 Refresh Token 轮换:每次续签时颁发新的 Refresh Token,旧的一个立即失效。这样攻击者只能使用一次,且服务端可检测异常(如一个 Refresh Token 被用了两次)。此外,还可以绑定设备指纹或 IP 来增强安全性。

追问3:为什么 Access Token 通常用 JWT,而 Refresh Token 有时要存数据库?

Access Token 需要高频验证,用无状态的 JWT 性能好;Refresh Token 需要支持吊销、轮换、次数记录等,通常用数据库或 Redis 存储状态,便于精细控制。

缓存

缓存到底存的是什么?

你打开商城首页,看到"全部商品"那一页,这一页数据在 Redis 里存的样子是:

复制代码
key:   "product:list::1:12"
value: [商品A, 商品B, 商品C ... 一共12个商品]

这就是缓存:把一整个页面内容存起来,下次再来就直接拿,不用查数据库。


为什么不同条件要拆开存?

假设你是老板,商场里有三个货架,每个货架摆法完全不一样

货架 摆法
默认排序 最新商品摆最前面
价格升序 最便宜的摆最前面
价格降序 最贵的摆最前面

这三个货架的顺序完全不同,必须分开记。

同样道理:

复制代码
product:list:手机::1:12      → [华为新品, iPhone15, ...]   按最新时间排
product:list:手机:price_asc:1:12 → [红米, iPhoneSE, iPhone15, ...] 按最便宜排

这两份数据长得不一样,不能放同一个格子里,否则会乱套。


为什么 page 也要存?

因为每个货架有 10 页。你是老板,你不能把所有商品全写在同一张纸上------纸太长了。你分 10 页写:

内容
第 1 页 商品 A, B, C ... L
第 2 页 商品 M, N, O ... X
第 3 页 商品 Y, Z ...

如果你把第 1 页和第 2 页的东西混在一起存,那当用户想看第 1 页时,你会分不清哪些是该给他看的。

总结成一句话

每个不同组合(不同分类 + 不同排序 + 不同页)都是不同的"页面",每个页面单独存一份缓存。 这就像给 150 张不同的照片各拍了一张拍立得,哪张被看到了就拿出来用,不用重新拍。

用户有多少种玩法,就有多少种缓存

Key 就是"地址标签"

复制代码
CacheConstants.PRODUCT_LIST = "product:list:"   ← 固定前缀,告诉"这是商品列表"
                        "手机"  ← 分类
                        ":"  ← 分隔符
                     "price_asc"  ← 排序方式
                        ":"  ← 分隔符
                          "1"  ← 第几页
                        ":"  ← 分隔符
                         "12"  ← 每页几条

最终 Key = product:list:手机:price_asc:1:12

Value 就是那个页面的数据

复制代码
[红米, ¥999, 库存200件], [iPhone SE, ¥3499, 库存50件], ... 共12条

(实际存的是 JSON 字符串,就是这 12 个商品的完整信息)

回答你最后的问题

用户不管怎么排序,我都有对应的缓存是吗?

不是一开始就有的 ,是"谁先点,谁触发创建":

用户操作 Key 状态
第一个人打开首页 product:list::1:12 没有缓存 → 查 DB → 写缓存
第二个人打开首页 product:list::1:12 缓存命中 → 直接返回
有人点"价格升序" product:list::price_asc:1:12 没有缓存 → 查 DB → 写缓存
后来又有个人点"价格升序" product:list::price_asc:1:12 缓存命中 → 直接返回

只要有一个用户选过这个组合,这个组合就会被缓存,后面来的人全走缓存。 如果永远没人选"价格降序第 3 页",它也不会被创建,不占内存。

这种方法叫做惰性缓存(lazy caching)------按需生成,按需缓存。

碎碎念:后续会更新每天学习的八股和算法 题,开始准备秋招的第16天。努力连续更新100天!以后每天就按,秋招项目【java+agent】,科研,必做项目,算法,八股,锻炼身体来总结。今天效率一般。明天加油!!!

总结:不要放弃呀,

1.算法要系统过一遍【灵神】2/27

2.秋招项目,【java】开始实际看业务,2/10;【agent】还在学,决定把helloagent看一遍,3/16

3.科研要跑一下,无

4.检测项目也得总结文档,无,

5.训练项目看看先选择好,无

6.背八股,无

7.锻炼身体,1h

昨天玩手机三点才睡觉欸嘿嘿,今天状态不好,明天再接再厉!

【要吃好喝好睡好!!!保持心情愉悦】

相关推荐
闪电悠米1 小时前
黑马点评-优惠券秒杀-03_basic_seckill_and_oversell
java·数据库·spring boot·spring·缓存·oracle·面试
不吃土豆的马铃薯1 小时前
TCP 三次握手 / 四次挥手详解
服务器·开发语言·网络·c++·网络协议·tcp/ip
一只老丸1 小时前
HOT100题打卡第27天——动态规划(hard)
算法·动态规划
羑悻的小杀马特1 小时前
【动态规划篇】正则表达式与通配符:开启代码匹配的赛博奇幻之旅
c++·算法·leetcode·正则表达式
ch.ju1 小时前
Java程序设计(第3版)第四章——引用
java·开发语言
吴可可1231 小时前
SolidWorks二次开发实战应用
算法
霸道流氓气质1 小时前
在Qoder中指定JDK和Maven运行AI学习的SpringBoot项目的完整指南
java·人工智能·maven
老码观察2 小时前
设计模式实战解读(七):适配器模式——让不兼容的接口无缝协作
java·设计模式·适配器模式
garmin Chen2 小时前
rabbitmq(1):核心机制与 SpringAMQP 详解
java·rabbitmq·java-rabbitmq