hot100【acm版】【2026.7.14打卡-java版本】

和为 K 的子数组

java 复制代码
package hot100;
import java.util.*;
public class lc560 {
    /*和为 K 的子数组
   给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
   子数组是数组中元素的连续非空序列。
   示例 1:
    输入:nums = [1,1,1], k = 2
    输出:2
   */

    //前缀和
    public int subarraySum(int[] nums, int target){
        Map<Integer,Integer> map = new HashMap<>();
        int sum = 0;
        int ans = 0;
        map.put(0,1);
        for(int i = 0; i < nums.length; i++){
            sum+=nums[i];
            if(map.containsKey(sum - target)){
                ans+=map.get(sum - target);
            }

            map.put(sum, map.getOrDefault(sum,0)+1);

        }

        return ans;
    }

    public static void main(String[] args) {
        lc560 solution = new lc560();
        int[] nums = new int[]{1,1,1};
        System.out.println("答案:" + solution.subarraySum(nums,2));
    }



}

滑动窗口最大值

java 复制代码
package hot100;

import java.util.ArrayList;
import java.util.*;

public class lc239 {
    /*
    239. 滑动窗口最大值
    给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。
    你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
    返回 滑动窗口中的最大值 。
    示例 1:
    输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
    输出:[3,3,5,5,6,7]
    解释:
    滑动窗口的位置                最大值
    ---------------               -----
    [1  3  -1] -3  5  3  6  7       3
     1 [3  -1  -3] 5  3  6  7       3
     1  3 [-1  -3  5] 3  6  7       5
     1  3  -1 [-3  5  3] 6  7       5
     1  3  -1  -3 [5  3  6] 7       6
     1  3  -1  -3  5 [3  6  7]      7
    *
    * */

    public int[] maxSlidingWindow(int[] nums, int target){
        //第一次做还是不会

        //堆?[不能限定位置]
        int[] ans = new int[nums.length - target +1];
        //滑动窗口
        //我只能想到暴力?
        //单调队列,
        Deque<Integer> queue = new ArrayDeque<>();

        //存的是下标,所以需要nums【下标】才能得到具体的数值去比大小

        for(int i = 0; i < nums.length; i++){
            //大于,从Last开始的

            //入栈就是比Last这段
            while(queue.size() >0 && nums[i]>=nums[queue.getLast()]){
                queue.removeLast();
            }
            queue.addLast(i);

            //出栈才是first这头,这个队列从大到小
            if((i - target +1) >0 && queue.getFirst() < i - target + 1){
                queue.removeFirst();
            }

            if(i >= target -1){
                ans[i-target+1] = nums[queue.getFirst()];
            }
        }

        return ans;

    }

    public static void main(String[] args) {
        int[] nums = new int[]{1,3,-1,-3,5,3,6,7};
        int k = 3;

        lc239 solution = new lc239();
        int[] sout =  solution.maxSlidingWindow(nums, k);
        for(int num : sout){
            System.out.println(num+ " ");
        }
    }
}

最小覆盖子串

java 复制代码
package hot100;

import java.util.Arrays;

public class lc76 {

    //写了一半,没写完整,只能说有思路, 针对后面缩小窗口要用while
    /*最小覆盖子串
    给定两个字符串 s 和 t,长度分别是 m 和 n,返回 s 中的 最短窗口 子串,
    使得该子串包含 t 中的每一个字符(包括重复字符)。如果没有这样的子串,返回空字符串 ""。
    测试用例保证答案唯一。
    示例 1:
    输入:s = "ADOBECODEBANC", t = "ABC"
    输出:"BANC"
    解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
    * */

    public String  minWindow(String s, String p){
        //先找到然后开始 int[字母]是满足的,然后看看能不能缩减
        //后续判断
        String ans = "";

        int[] pLen = new int[128];
        int[] sLen = new int[128];
        for(int i = 0; i < p.length(); i++){
            pLen[p.charAt(i) ]++;
        }
        int psum = 0;
        for(int i = 0; i < 128; i++){
            if(pLen[i]>0){
                psum++;
            }
        }

        int left = 0;
        int right = 0;
        int ssum = 0;
        while(right < s.length()){

            sLen[s.charAt(right)]++;

            if(pLen[s.charAt(right)] >0 && sLen[s.charAt(right)] == pLen[s.charAt(right)]){
                ssum++;
            }

            while(ssum == psum && left <= right) {
                //里面的数量肯定达标了,字母缩减?
                if (sLen[s.charAt(left)] > pLen[s.charAt(left)]) {
                    sLen[s.charAt(left)]--;
                    left++;
                } else {
                    break;
                }
            }

            //已经是最小窗口
            if (ssum == psum) {
                String temp = s.substring(left, right + 1);
                if (ans.isEmpty() || temp.length() < ans.length()) {
                    ans = temp;
                }
                // 为了继续寻找更小的窗口,左指针右移一位,并更新计数
                char leftChar = s.charAt(left);
                sLen[leftChar]--;
                //相减也要看ssum
                if (pLen[leftChar] > 0 && sLen[leftChar] < pLen[leftChar]) {
                    ssum--;
                }
                left++;
            }


            right++;

        }

        return ans;
    }

    public static void main(String[] args) {
        String s = "ADOBECODEBANC";
        String t = "ABC";
        lc76 solution = new lc76();

        System.out.println(solution.minWindow(s, t));
    }
}

最大子数组和

java 复制代码
package hot100;
import java.util.*;
public class lc53 {

    /*
    最大子数组和
    给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
    子数组是数组中的一个连续部分。
    示例 1:
    输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
    输出:6
    解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
    * */

    //贪心?
    public int maxSubArray(int[] nums){
        int[] dp = new int[nums.length];
        int max = nums[0];
        dp[0] = nums[0];
        for(int i = 1; i < nums.length; i++){
            dp[i] = Math.max(dp[i-1], 0) + nums[i];
            max = Math.max(max,dp[i]);
        }

        return max;
    }

    //优化的版本,只需要pre就行
    public int maxSubArray1(int[] nums){
        int pre = nums[0];
        int max = nums[0];

        for(int i = 1; i < nums.length; i++){
            pre= Math.max(pre, 0) + nums[i];
            max = Math.max(max,pre);
        }

        return max;
    }

    public static void main(String[] args) {
        lc53 solution = new lc53();
        int[] nums = new int[]{-2,1,-3,4,-1,2,1,-5,4};
        System.out.println("答案:" + solution.maxSubArray1(nums));
    }

}

合并区间

java 复制代码
package hot100;

import java.util.*;

public class lc56 {

    //第一次没写出来
    /*
    * 56. 合并区间
    以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。
    *请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
    示例 1:
    输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
    输出:[[1,6],[8,10],[15,18]]
    解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].*/

    public int[][] merge(int[][] intervals){
        //排序不会写,get[i],api不会写
        Arrays.sort(intervals,(p,q)->p[0]-q[0]);

        //int[][]用list
        List<int[]> ans = new ArrayList<>();

        for(int[] interval : intervals){
            if(ans.size() >0 && ans.get(ans.size() -1)[1]>= interval[0]){
                //按顺序存的,按顺序取
                ans.get(ans.size() -1)[1] = Math.max(ans.get(ans.size()-1)[1],interval[1]);
            }else{
                ans.add(interval);
            }
        }

        //list转数组
        return ans.toArray(new int[ans.size()][]);
    }

    public static void main(String[] args) {
        lc56 soulution = new lc56();
        int[][] nums = new int[][] {{1, 3}, {2, 6}, {8, 10}, {15, 18}};
        int[][] result = soulution.merge(nums);

        for(int[] s : result){
            System.out.println(Arrays.toString(s));
        }

    }

}

随机知识

1. AQS是什么?ReentrantLock的实现原理?

  • AQS (AbstractQueuedSynchronizer)是Java并发包的核心框架,基于state状态变量 + CLH队列实现。

  • 加锁流程:线程尝试CAS将state从0改为1,成功则获取锁并设置独占线程;失败则进入CLH队列尾部自旋或挂起等待。

  • 可重入:state记录重入次数,获取一次+1,释放一次-1,为0时锁完全释放。

  • 公平锁 :先判断队列是否有前驱节点,有则排队;非公平锁:上来就CAS抢锁,抢不到再排队。

  • 与Synchronized区别:ReentrantLock可手动控制加锁释放、支持公平锁、可中断获取锁、可tryLock超时,但需手动释放。


2. volatile关键字的作用和原理?

两大作用:

  • 可见性:一个线程修改volatile变量后,立即刷新到主内存,其他线程读时强制从主内存重新加载。

  • 禁止指令重排序:通过内存屏障实现,保证volatile写之前的操作不会被重排到写之后,读之后的操作不会被重排到读之前。

  • 内存屏障:写操作前插入StoreStore屏障,写后插入StoreLoad屏障;读操作后插入LoadLoad和LoadStore屏障。

  • 不保证原子性:i++这种复合操作,volatile无能为力,仍需synchronized或Atomic类。

  • 应用场景:单例模式的双重检查锁定(DCL),用volatile修饰instance防止指令重排导致半初始化对象逃逸。


3. Spring事务的传播行为有哪些?常用的两个解释一下?

七种传播行为,最常用:

  • REQUIRED(默认):有事务就加入,没有就新建。调用方有事务,被调用方就共享一个事务,一方回滚全部回滚。

  • REQUIRES_NEW:始终新建独立事务,如果调用方有事务就挂起它。二者互不影响,各自提交或回滚。

  • 其他:SUPPORTS(有就加入没有也无所谓)、NOT_SUPPORTED(非事务执行)、MANDATORY(必须有事务否则抛异常)、NEVER(必须没事务)、NESTED(嵌套事务,通过保存点实现部分回滚)。

  • 坑点 :同类方法调用不走代理,事务失效;非public方法默认不走事务;异常被catch住不抛出,事务不回滚(除非手动设置TransactionAspectSupport.currentTransactionStatus().setRollbackOnly())。


4. Redis的缓存穿透、击穿、雪崩是什么?如何解决?

  • 缓存穿透:查询不存在的数据,缓存没命中,请求直达数据库。

    • 解决:布隆过滤器过滤不存在的key;或把null值也缓存,设置较短过期时间。
  • 缓存击穿:热点key过期瞬间,大量并发请求同时打到数据库。

    • 解决:互斥锁(只有一个线程去加载DB并回写缓存,其他等待);或逻辑过期(永不过期,后台异步刷新)。
  • 缓存雪崩:大量key同时过期,或Redis宕机,所有请求打到数据库。

    • 解决:过期时间加随机值打散;Redis集群高可用(主从+哨兵);限流降级保护数据库;多级缓存。

5. MySQL的事务隔离级别有哪些?InnoDB如何解决幻读?

四种隔离级别:

  • 读未提交:可读到未提交数据,有脏读问题。

  • 读已提交:只能读已提交数据,解决脏读,但有不可重复读和幻读。

  • 可重复读(InnoDB默认):同一事务多次读取结果一致,解决不可重复读,部分解决幻读。

  • 串行化:事务完全串行执行,解决所有问题,性能最差。

InnoDB如何解决幻读?

  • MVCC快照读:普通SELECT读的是快照版本,不受其他事务插入影响,解决快照幻读。

  • 间隙锁+临键锁SELECT ... FOR UPDATE这种当前读,会在查询范围加间隙锁(锁住索引间隙)和临键锁(行锁+间隙锁),阻止其他事务在范围内插入数据,解决当前读的幻读。

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

总结:继续总结项目

1.hot100 【acm】 14/100 ,有点手感了,2到3h,快速把hot100过一遍【20天看看行不行】

2.秋招项目,【java 项目】,

【agent 项目 】,看来一遍打算面向面试拷打一下

3.科研。确定方向就搞就可以了

4.实习;上班干杂活2h

6.背八股,无

7.锻炼身体,无

要点:坚持,今天还是松懈了点,一天摸鱼加学习能学6-7h大概

相关推荐
Zane19944 分钟前
用了Optional,为什么NPE还是防不住?
java·后端
晚安日记wanna4 分钟前
批量请求失败只弹一个 Toast面试官想听五层
前端·面试·架构
大模型码小白9 分钟前
告别造假数据,直接连数据库查真实时序数据喂给 TimechoAI 大模型
java·数据库·人工智能·microsoft·架构
晚安日记wanna11 分钟前
TS const 类型参数一道面试题的四层追问
前端·面试·typescript
企业数字化笔记12 分钟前
固定资产Excel批量导入怎么防重复?资产编码、重复检查和错误回执
java·后端·excel
晚安日记wanna12 分钟前
大表 DDL 面试翻车现场Online DDL 为什么还会锁死业务
数据库·面试·架构
晚安日记wanna15 分钟前
MySQL 主从延迟别只答并行复制
数据库·面试·架构
golang学习记17 分钟前
IDEA 2026.3 EAP新特性:自动识别Spring Boot的新 profile 了
java·spring boot·intellij-idea
SamDeepThinking23 分钟前
Java 17内存屏障:为什么需要,怎么用
java·后端·面试
青山木26 分钟前
Hot 100 --- 最长递增子序列
java·数据结构·算法·leetcode·动态规划