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大概

相关推荐
cpp_25011 小时前
P10098 [ROIR 2023] 地铁建设 (Day 2)
数据结构·c++·算法·贪心·二分答案·洛谷题解
thefool1122662 小时前
Java 数组是引用类型
java
阳明山水2 小时前
TimesFM与Moirai MoE零样本预测解析
人工智能·深度学习·算法·机器学习·架构
铅笔侠_小龙虾2 小时前
Rust 学习(2)-变量、常量与 shadowing
学习·算法·rust
cfm_29143 小时前
Spring监听器
java·spring boot·后端
AI科技星3 小时前
基于全域数学公理体系的三元极值题最简求解法【乖乖数学】
线性代数·算法·游戏·决策树·机器学习·乖乖数学·全域数学
SamDeepThinking3 小时前
Java面向对象在JVM里怎么实现
java·后端·面试
大鱼>3 小时前
宠物异常行为预警系统:边缘计算与实时检测
人工智能·深度学习·算法·iot·宠物
咸鱼翻身小阿橙4 小时前
多线程解析
java·开发语言