leecodecode【回溯组合】【2026.6.5打卡-java版本】

组合

要点

方法1:dfs传什么【start,depth,+常规的四个】

java 复制代码
class Solution {
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> ans = new ArrayList<>();
        int[] path = new int[k];
        dfs(1,0,n,k,path,ans);
        return ans;
        
    }


    public void dfs(int start, int depth, int n, int k, int[] path, List<List<Integer>> ans){
        
        if(depth == k){
            List<Integer> list = new ArrayList<>();
            for (int num : path) {
               list.add(num);
            }
            ans.add(list);
            return;
        }
        //int temp = i+1;
        for(int j = start; j <= n; j++){
            path[depth] = j;
            dfs(j+1,depth+1,n,k,path,ans);

        }
    }
}

方法2:枚举,for,下一个是dfs(j-1),从后往前, d = k - path.size()

java 复制代码
class Solution {
    public List<List<Integer>> combine(int n, int k) {
        //枚举下一个数字选什么
        List<List<Integer>> ans = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        dfs(n,  k, path,ans);
        return ans;
        
    }


    public void dfs(int i, int k, List<Integer> path, List<List<Integer>> ans){
        int d = k - path.size();
        if(d == 0){
            ans.add(new ArrayList<>(path));
            return;
        }

        for(int j = i; j >= d; j--){
            path.add(j);
            dfs(j-1,k,path,ans);
            path.removeLast();
        }
    }
}

方法3:选还是不选

java 复制代码
class Solution {
    public List<List<Integer>> combine(int n, int k) {
        //枚举下一个数字选什么
        List<List<Integer>> ans = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        dfs(n,  k, path,ans);
        return ans;
        
    }


    public void dfs(int i, int k, List<Integer> path, List<List<Integer>> ans){
        int d = k - path.size();
        if(d == 0){
            ans.add(new ArrayList<>(path));
            return;
        }

       //不选i
       if(i>d){
        dfs(i-1, k, path,ans);
       }

       //选
       path.add(i);
       dfs(i-1,k, path, ans);
       path.removeLast();
    }
}

组合总和 III

要点:

方法1:枚举,剪枝,dfs(j-1, k, n-j,path,ans)

java 复制代码
class Solution {
    public List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> ans = new ArrayList<>();
        List<Integer> path = new ArrayList<>();

        dfs(9,k,n,path, ans);

        return ans;
        
    }


    public void dfs(int i, int k, int n, List<Integer> path, List<List<Integer>> ans){
        int d = k - path.size();

        if(n <0 || n > (i * 2 - d + 1) * d / 2 ){
            return;
        }


        if(d == 0 && n ==0){
            ans.add(new ArrayList<>(path));
            return;
        }

        for(int j = i ; j >= d; j--){
            path.add(j);
            dfs(j-1,k,n-j,path,ans);
            path.removeLast();
        }
    }
}

方法2:选还是不选

java 复制代码
class Solution {
    public List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> ans = new ArrayList<>();
        List<Integer> path = new ArrayList<>();

        dfs(9,k,n,path, ans);

        return ans;
        
    }

    public void dfs(int i, int k, int n, List<Integer> path, List<List<Integer>> ans){
        int d = k - path.size();

        if(n <0 || n > (i * 2 - d + 1) * d / 2 ){
            return;
        }


        if(d == 0 && n ==0){
            ans.add(new ArrayList<>(path));
            return;
        }
        //不选
        if(i > d){
            dfs(i-1,k,n,path,ans);
        }

        //选择
        path.add(i);
        dfs(i-1,k,n-i,path,ans);
        path.removeLast();

    }
}

括号生成

要点:选还是不选,left,right,什么时候return【right == n】

java 复制代码
class Solution {
    public List<String> generateParenthesis(int n) {
        //选或者不选
        List<String> ans = new ArrayList<>();

        char[] path = new char[n*2];

        dfs(0,0, n,path, ans);

        return ans;
        
    }


    public void  dfs(int left, int right,int n,char[] path, List<String>ans){

        if(right == n){
            ans.add(new String(path));
            return;
        }

        if(left < n){
            path[left+right] = '(';
            dfs(left+1,right, n, path, ans);
        }

        if(right < left){
            path[left+right] =')';
            dfs(left, right+1, n, path, ans);
        }
    }
}

随机知识

三、持久化机制(高频)

RDB 和 AOF 有什么区别?你平时用什么?

面试官为什么这么问?

这题考察你对数据安全性和性能的权衡思维。我要看你是否知道它们各自的工作原理、优缺点,以及混合持久化的好处。

希望听到怎样的回答:

  • RDB :快照持久化,某个时刻把整个内存写入 .rdb 文件。
    • 优点:文件紧凑,恢复快,适合冷备。
    • 缺点:两次快照之间的数据可能丢失(最近几分钟),生成快照时如果 Fork 子进程会阻塞主进程(对大数据集)。
  • AOF :追加写命令,记录到 .aof 文件,默认每秒 Fsync。
    • 优点:数据安全性高,最多丢失 1 秒数据;文件可读可重写;能用 bgrewriteaof 压缩。
    • 缺点:AOF 文件通常比 RDB 大,恢复慢。
  • 混合持久化(Redis 4.0+):RDB 写全量,AOF 补增量,结合两者优点。

候选人

好的。RDB 和 AOF 是 Redis 的两种持久化机制,它们的核心区别在于持久化的时机数据的完整性。我从原理、优缺点和实际选型三个角度来讲。

第一,RDB 持久化。

RDB 是快照持久化 ,它把 Redis 在某个时间点的整个内存数据拍成一个"照片",写入到一个二进制的 .rdb 文件里。

触发方式有两种:一种是自动触发,在配置里写 save 900 1 之类的规则(900 秒内至少一个 key 变化就触发);另一种是手动执行 BGSAVE 命令。BGSAVE 会 fork 一个子进程来做快照,主进程继续处理请求。fork 过程利用了操作系统的写时复制机制------fork 的瞬间内存数据被标记为只读,主进程需要修改某个数据时,系统会先把这个数据页复制一份,主进程改新副本,子进程继续读旧版本。这样快照数据是 fork 时刻的一致性快照,不额外占用大量内存。

优点:文件紧凑,恢复大容量数据非常快,适合冷备、异地灾备这些场景。把 rdb 文件传到其他服务器直接加载就行。

缺点:两次快照之间有数据丢失的风险。如果配置 5 分钟保存一次,在这 5 分钟内 Redis 宕机,最近 5 分钟的数据全部丢失。另外,fork 子进程在大数据集下耗时较长,期间 Redis 的写时复制也会消耗额外内存和 CPU,对性能有一定影响。

第二,AOF 持久化。

AOF 是追加写命令的日志 。它把 Redis 执行的每一条写命令都记录到 .aof 文件末尾,就像 MySQL 的 binlog。Redis 重启时,把 AOF 文件里的命令重新执行一遍来恢复数据。

刷盘策略有三种:always 每条命令都立即刷盘,数据最安全但性能最差;everysec 每秒刷一次,最多丢失 1 秒数据,性能和安全性最平衡;no 交给操作系统刷盘,性能最好但可能丢失较多数据。默认是 everysec

AOF 有一个重要的优化叫 AOF 重写(bgrewriteaof)。随着写入越来越多,AOF 文件会越来越大,很多记录其实是对同一个 key 的反复修改,只有最后一次有效。Redis 在后台 fork 子进程,根据当前内存数据的最终状态,生成一份新的最精简的 AOF 文件,替换掉老的。重写过程不影响主进程写操作------重写期间的增量命令会写入一个缓冲区,重写完成后追加到新文件末尾。

优点:数据安全性更高,最多就丢 1 秒的数据;AOF 是人类可读的文本格式,极端情况下可以手动修改恢复。

缺点:AOF 文件通常比 RDB 大;恢复时需要逐条重放命令,速度比 RDB 慢。如果 AOF 文件损坏或格式错误,启动时可能修复失败。

第三,混合持久化。

Redis 4.0 开始支持混合持久化,结合了 RDB 和 AOF 的优点。在 AOF 重写时,子进程把当前内存数据以 RDB 二进制格式写入新 AOF 文件的开头,之后的增量命令以 AOF 格式追加在后面。最终文件结构是 [RDB 快照][AOF 增量命令]

恢复时,Redis 先快速加载 RDB 部分(恢复大部分数据),再执行 AOF 尾部少量增量命令(补齐最新数据),比纯 AOF 恢复快很多。数据安全性上,everysec 依然保证最多丢失 1 秒数据。

如果 Redis 支持 4.0 以上版本,且需要兼具恢复速度和数据安全性,混合持久化是最佳选择。

第四,项目中的实际选型。

我项目里的 Redis 有双重用途:缓存层和极少数轻量状态存储。具体选择取决于数据的重要性。

对于题目缓存、排行榜这类纯缓存数据,数据库里有完整的数据源,挂了重建就是。这部分数据只开 RDB,关闭 AOF(减少写磁盘开销和文件体积)。RDB 做冷备,提供宕机后快速恢复大部分热数据的能力,几分钟的数据空缺从数据库补回来。

对于部分用户会话状态、业务进度标记等不允许丢失的关键数据,开启混合持久化 + everysec 刷盘,保证最多丢失 1 秒数据,且重启加载快。

高可用方面不能只靠持久化,主从复制加哨兵模式是默认方案。主节点故障时自动切换,持久化文件是最后的兜底。


总结一句话:RDB 重冷备和恢复速度,AOF 重数据安全性,混合持久化兼具两者优点,实际选型看数据丢失的容忍度------缓存类低风险数据用 RDB,需要高安全性的状态数据用混合持久化。线上高可用核心靠主从和哨兵,持久化文件是最后一道保险。

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

总结:项目的代码起码还是要逻辑理清楚,看懂,不然一点下问题都要搞半天

1.算法要系统过一遍【灵神】15/27【早上】大概1.5h

2.秋招项目,【java】开始实际看业务,2.9/10;无

【agent】还在学,无

3.科研要跑一下,无,

4.检测项目也得总结文档,6h+,【今天深度思考了,但是效果还是不好生气啊啊啊】

5.训练项目,无

6.背八股,无

7.锻炼身体,无

反思:今天想把检测羡慕搞一下,但是还没搞好,晚上看来下浪姐直播,好生气可恶!!

早睡早起,每天继续努力,时间分布还是要均匀点哇。

相关推荐
8Qi81 小时前
LeetCode 518:零钱兑换 II(Coin Change II)—— 题解 ✅
java·算法·leetcode·动态规划·完全背包
cfm_29141 小时前
SpringBoot整合RocketMQ极速实战
java·spring boot·后端
为爱停留1 小时前
让智能体「记住」对话:Checkpoint 功能、持久化数据接口与 thread_id 详解
java·数据库·elasticsearch
Sylvia33.1 小时前
2026世界杯全套数据API接入教程:WebSocket实时进球推送实例
java·网络·python·websocket·网络协议
zyl837211 小时前
Python 线性代数:矩阵与向量
开发语言·python·机器学习
linge_sun1 小时前
SpringAI 功能体验之SQL智能助手:用自然语言查询数据库
java·人工智能·ai编程
AC赳赳老秦1 小时前
OpenClaw+MySQL 深度应用:自动生成建表语句、索引优化建议与数据迁移脚本
开发语言·数据库·人工智能·python·mysql·算法·openclaw
yangyongdehao301 小时前
桌面宠物开发记:从Rust到Tauri的探索之旅
开发语言·rust·宠物
想取一个与众不同的名字好难2 小时前
安卓设置亮度的时候,系统会在100%与0%反复横跳
android·java·开发语言