LeetCode Hot100(69/100)—— 139. 单词拆分

Macbook Pro上如何修改brew源 一、需求说明 我的macbook电脑安装了中科大的brew源码,发现安装gpg工具失败,其他工具可以正常安装,为了能将gpg安装成功,就找了找切换brew源的方案,记录如下。 二、切换至国内源 由于使用github默认源有可能存在路径远或者部分服务访问超时的原因,切换至国内源可以提速。 2.1 替换brew.git $ cd "$(brew --repo)" # 中国科大: $ git remote set-url origin https://mirrors.ustc.edu.cn/brew.git # 阅读详情

题目链接

https://leetcode.cn/problems/word-break/description/

题目说明

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s。

注意: 不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例

示例 1:

输入: s = "leetcode", wordDict = ["leet","code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。

示例 2:

输入: s = "applepenapple", wordDict = ["apple","pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。
注意,你可以重复使用字典中的单词。

示例 3:

输入: s = "catsandog", wordDict = ["cats","dog","sand","and","cat"]
输出: false

约束条件

  • 1 <= s.length <= 300
  • 1 <= wordDict.length <= 1000
  • 1 <= wordDict[i].length <= 20
  • s 和 wordDict[i] 仅由小写英文字母组成
  • wordDict 中的所有字符串互不相同

解题思路概览

单词拆分问题

方法1: 动态规划

方法2: 记忆化搜索

方法3: BFS广度优先搜索

自底向上构建

状态转移方程

自顶向下递归

缓存中间结果

队列存储位置

层次遍历

方法一:动态规划

原理讲解

动态规划是解决此题的最优方法。核心思想是:如果字符串的前 i 个字符可以被拆分,且从位置 i 到 j 的子串在字典中,那么前 j 个字符也可以被拆分。

定义状态:

  • dp[i] 表示字符串 s 的前 i 个字符是否可以被拆分成字典中的单词

状态转移方程:

dp[i] = dp[j] && wordDict.contains(s.substring(j, i))
其中 0 <= j < i

执行流程

否

是

是

否

开始

初始化dp数组, dp0=true

遍历i从1到n

遍历j从0到i-1

dp[j]==true?

s[j:i]在字典中?

dp[i]=true, break

返回dp[n]

Java代码实现

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        // 将字典转换为HashSet,提高查找效率
        Set<String> wordSet = new HashSet<>(wordDict);
        int n = s.length();
        
        // dp[i]表示s的前i个字符是否可以被拆分
        boolean[] dp = new boolean[n + 1];
        dp[0] = true; // 空字符串可以被拆分
        
        // 遍历字符串的每个位置
        for (int i = 1; i <= n; i++) {
            // 尝试所有可能的拆分点
            for (int j = 0; j < i; j++) {
                // 如果前j个字符可以拆分,且j到i的子串在字典中
                if (dp[j] && wordSet.contains(s.substring(j, i))) {
                    dp[i] = true;
                    break; // 找到一种拆分方式即可
                }
            }
        }
        
        return dp[n];
    }
}

复杂度分析

  • 时间复杂度:O(n² × m),其中 n 是字符串长度,m 是字典中最长单词的长度(substring操作)
  • 空间复杂度:O(n),dp数组的空间

方法二:记忆化搜索(DFS + 缓存)

原理讲解

记忆化搜索采用自顶向下的递归思路,从字符串的起始位置开始,尝试匹配字典中的每个单词。为了避免重复计算,使用一个缓存数组记录每个位置的搜索结果。

执行流程

字典 缓存数组 DFS递归 主函数 字典 缓存数组 DFS递归 主函数 dfs(0) 检查memo[0] 未计算 遍历字典单词 匹配"leet" dfs(4) 检查memo[4] 未计算 匹配"code" 到达末尾 memo[4]=true memo[0]=true 返回true

Java代码实现

class Solution {
    private Boolean[] memo;
    private Set<String> wordSet;
    private String s;
    
    public boolean wordBreak(String s, List<String> wordDict) {
        this.s = s;
        this.wordSet = new HashSet<>(wordDict);
        this.memo = new Boolean[s.length()];
        return dfs(0);
    }
    
    private boolean dfs(int start) {
        // 到达字符串末尾,说明可以完全拆分
        if (start == s.length()) {
            return true;
        }
        
        // 如果已经计算过,直接返回缓存结果
        if (memo[start] != null) {
            return memo[start];
        }
        
        // 尝试从start位置开始匹配字典中的每个单词
        for (String word : wordSet) {
            int end = start + word.length();
            // 检查是否越界以及是否匹配
            if (end <= s.length() && s.substring(start, end).equals(word)) {
                // 递归检查剩余部分
                if (dfs(end)) {
                    memo[start] = true;
                    return true;
                }
            }
        }
        
        // 所有尝试都失败
        memo[start] = false;
        return false;
    }
}

复杂度分析

  • 时间复杂度:O(n × k × m),其中 n 是字符串长度,k 是字典大小,m 是平均单词长度
  • 空间复杂度:O(n),递归栈和缓存数组的空间

方法三:BFS广度优先搜索

原理讲解

将问题看作图的遍历问题,每个位置是一个节点,如果从位置 i 到位置 j 的子串在字典中,则存在一条从 i 到 j 的边。使用BFS从位置0开始,看能否到达位置n。

执行流程

leet

code

le

et

code

位置0

位置4

位置8/结束

位置2

位置4

Java代码实现

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        Set<String> wordSet = new HashSet<>(wordDict);
        Queue<Integer> queue = new LinkedList<>();
        boolean[] visited = new boolean[s.length()];
        
        queue.offer(0);
        
        while (!queue.isEmpty()) {
            int start = queue.poll();
            
            // 如果这个位置已经访问过,跳过
            if (visited[start]) {
                continue;
            }
            visited[start] = true;
            
            // 尝试从start位置开始的所有可能单词
            for (int end = start + 1; end <= s.length(); end++) {
                if (wordSet.contains(s.substring(start, end))) {
                    // 如果到达末尾,返回true
                    if (end == s.length()) {
                        return true;
                    }
                    // 将新位置加入队列
                    queue.offer(end);
                }
            }
        }
        
        return false;
    }
}

复杂度分析

  • 时间复杂度:O(n² × m),最坏情况下需要访问所有位置,每个位置需要检查所有可能的子串
  • 空间复杂度:O(n),队列和visited数组的空间

优化技巧

动态规划优化版本

可以通过记录字典中最长单词的长度来减少内层循环次数:

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        Set<String> wordSet = new HashSet<>(wordDict);
        int n = s.length();
        
        // 找出字典中最长单词的长度
        int maxLen = 0;
        for (String word : wordDict) {
            maxLen = Math.max(maxLen, word.length());
        }
        
        boolean[] dp = new boolean[n + 1];
        dp[0] = true;
        
        for (int i = 1; i <= n; i++) {
            // 只需要检查最长单词长度范围内的拆分点
            for (int j = Math.max(0, i - maxLen); j < i; j++) {
                if (dp[j] && wordSet.contains(s.substring(j, i))) {
                    dp[i] = true;
                    break;
                }
            }
        }
        
        return dp[n];
    }
}

方法对比分析

方法时间复杂度空间复杂度实现难度性能表现适用场景
动态规划O(n² × m)O(n)中等最优通用场景,推荐使用
动态规划优化O(n × maxLen × m)O(n)中等优秀字典单词长度差异大时效果显著
记忆化搜索O(n × k × m)O(n)中等良好字典较小时表现好
BFSO(n² × m)O(n)简单一般理解图论思想的教学场景

性能对比说明

  1. 动态规划方法是最稳定和推荐的解法,代码简洁,性能优秀
  2. 优化后的动态规划在字典单词长度较短时能显著提升性能
  3. 记忆化搜索在字典规模较小时表现良好,但递归调用有额外开销
  4. BFS方法直观易懂,但在实际性能上略逊于动态规划

选择建议

  • 面试场景:优先使用动态规划,代码简洁且易于解释
  • 性能要求高:使用优化版动态规划
  • 学习理解:可以从BFS开始,逐步过渡到动态规划
  • 字典特别小:记忆化搜索也是不错的选择

单词拆分问题是一道经典的动态规划题目,核心在于理解状态定义和转移方程。通过将大问题分解为子问题,利用已计算的结果来避免重复计算,可以高效地解决这个问题。掌握这道题的多种解法,有助于深入理解动态规划、记忆化搜索和BFS等算法思想。

web渗透--9--识别web应用框架 1、概述 Web框架指纹识别是信息收集过程中的一个重要任务。获悉目标框架的类型必然为测试人员带来极大的优势,如果该框架在之前就被测试过。测试人员不仅可以获得未修补版本中存在的漏洞,还可以了解此框架中特有的错误配置以及已知的文件结构。从而使指纹识别过程显得格外重要。 阅读详情

相关推荐

7 series FPGAs Transceiver Wizard IP核使用和测试

学习FPGA一段时间了,前面一直没有系统的总结,这学期把在项目中用到的IP核和一些调试过程中遇到的问题总结一下发出来,坚持下去,一起进步! 今天总结一下的GTH核的使用和测试。 软件版本:Vivado 2017.4 IP核版本:7 Series FPGAs Transceivers Wizard (3.6) FPGA:xc7vx690tfft1927 实现功能: 四路光纤数据接收,由于GTX IP...

qq_39921762的博客 1万+

力扣hot100

【代码】力扣hot100。

qq_59768361的博客 1400

PBR:双向反射分布函数(BRDF)介绍与Cook-Torrance模型的实现

PBR:双向反射分布函数(BRDF)介绍与Cook-Torrance模型的实现 BRDF简介 再介绍BRDF之前我们要引入渲染方程这个东西: 其中L表示辐射率,其公式为: 它表示了一个拥有辐射强度Φ的光源在单位面积A,单位立体角ω上的辐射出的总能量。 辐射率是辐射度量学上表示一个区域平面上光线总量的物理量,它受到入射光线与平面法线间的夹角θ的余弦值cosθ的影响:当直接...

小龙虾的博客 1万+

Hot 100总结【leetcode】

leetcode hot100总结

weixin_44911248的博客 6639

专访高性能计算专家赵开勇:无人机/机器人开发实战,如何优化深度学习?

从能够自主飞行的无人机,到能和小朋友玩物体识别等游戏的机器人,极客们对智能设备追求没有止境。除了轻巧的体积、超长的续航,更重要的是要有一个智能的“大脑”,来实现人类能够想得到的人机交互,或者智能化的自主决策和行为动作,毫无疑问强大的深度学习能力不可或缺。那么,拒绝束缚人类想象力的嵌入式智能设备,其开发工作需要什么样的环境和工具?开发者进行相关开发的可行思路是什么?近日,优快云记者就此专访了智能设...

happytofly的博客 3509

OpenHarmony 5.1 RK3568 开发板烧录:从源码编译到镜像写入的 6 步实战

本文详细解析了OpenHarmony 5.1在RK3568开发板上的全链路开发流程,包括环境搭建、源码编译、镜像烧录等6个关键步骤。通过实战指南和避坑技巧,帮助开发者快速掌握OpenHarmony系统的烧录与定制能力,提升物联网设备开发效率。

weixin_33722405的博客 343

【力扣Hot 100+经典题型】刷题记录(Python版)

力扣hot 100刷题记录

我的技术栈碎碎念空间 7842

【Bug已解决】openclaw max turns reached / Tool calls exceeded limit — OpenClaw 最大轮次超限解决方案

OpenClaw 在执行过程中达到最大轮次限制任务未完成,本质是 --max-turns 设置过小或任务过于复杂。文中给出增加轮次、--continue 继续、分步执行等完整方案。

一键难忘的博客 5505

LeetCode 热题 HOT 100 完整题解笔记&知识点分类 C++代码实现

1、知识点分布 2、完整代码

小哈里的博客 1万+

HyperLynx(十八)DDR(一)DDR简介和DDR的数据仿真

LVTTL电平为单端信号,而SSTL电平本质上是差分对,其实现机制是将信号与参考电平Vref组成差分对进行比较,如图所示,VIH和VIL各有一个交流参数AC和直流参数DC,信号第一次越过AC门限的时刻,作为时序计算的参考点,此后只要信号保持DC门限内,逻辑状态保持不变,这种设计减小了噪声、振铃等对于信号质量的影响。经过调整后,控制器在发送颗粒1的DQS后,延时1ns再发送颗粒2的DQS,则颗粒1在1ns后收到对齐的DQS和CLK,颗粒2在2ns后收到对齐的DQS和CLK,从而满足了时序关系。

小幽余生不加糖 7676

你知道几种数字地与模拟地连接方式及优缺点?

频率选择性:磁珠的阻抗特性随频率变化,只对某个频点的噪声有显著抑制作用,对于频率不确定或无法预知的情况,可能不是最佳选择。在实际应用中,选择合适的连接方式需要根据具体的电路频率、信号类型、设计要求等因素综合考虑,以达到最佳的电磁兼容效果.高频信号干扰:在高频电路中,单点接地可能导致信号回流路径过长,增加地线电感,从而引入高频噪声。限制噪声电流:0欧姆电阻相当于一个非常窄的电流通路,能够有效地限制环路电流,使噪声得到抑制。抑制高频信号:电感对高频信号有较大的阻碍作用,可以有效抑制高频噪声。

linkking27的博客 800

ms-hot目录

131. 长度为n的开心字符串中字典序第k小的字符串。126. 每个元音包含偶数次的最长子字符串。159. 得到连续K个1的最小相邻交换次数。190. 应用操作后不同二进制字符串的数量。38. 填充每个节点的下一个右侧结点指针。205. 使数组中所有元素相等的最小开销。208. 统计X和Y频数相等的子矩阵数量。138. 删除链表M个节点后的N个节点。167. 使数组元素相等的减少操作次数。177. 分享K个糖果后独特口味的数量。填充每个节点的下一个右侧结点指针II。104. 将数组分成和相等的三个部分。

JXH_123的专栏 567

游戏大厂状态同步与帧同步技术全解析——让虚拟世界万物协同的“时间齿轮”

本文深入解析了大厂游戏开发中的两种核心同步技术:状态同步和帧同步。状态同步适合大型MMO和FPS游戏,由服务端计算并广播世界状态;帧同步则通过统一操作输入实现MOBA和RTS游戏的绝对公平。文章详细比较了两者的差异、适用场景和底层实现原理,并揭秘了《王者荣耀》《PUBG》等热门游戏的同步机制。同时探讨了本地预测、延迟补偿、防作弊等关键技术,以及未来AI和云游戏带来的同步新挑战,为开发者提供了全面的技术参考和实践指南。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 919

LeetCode 面试经典 150_多维动态规划_交错字符串(97_C++_中等)

LeetCode 面试经典 150_多维动态规划_交错字符串(97_C++_中等) 题目描述: 给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串: - s = s1 + s2 + ... + sn - t = t1 + t2 + ... + tm - |n - m| <= 1 - 交错 是 s1 + t

huayimenghan的博客 205

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

LeetCode 每日一题 2026/11/2-2026/11/8

记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步

AlphaTao的博客 175

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

LeetCode Hot 100 二叉树专题(二)3 题(Java)

本篇文章共 3 题:543. 二叉树的直径、102. 二叉树的层序遍历、108. 将有序数组转换为二叉搜索树。 每道题都统一按「① 题目分析 & 解题思路 → ② 常见解法(附代码)及讲解 → ③ 知识点总结」的顺序组织;代码使用 Java 编写,节点定义沿用 LeetCode 默认的 TreeNode。

2401_88612756的博客 365

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

力扣73 矩阵置零

该解法通过标记含0的行和列来实现矩阵置零。遍历矩阵,用布尔数组记录有0的行和列;再遍历一次,若当前行或列被标记,则置为0。时间复杂度O(mn),空间复杂度O(m+n)。

Pniubi的博客 19

Hash表:两数之和、字母异位词分组、最长连续序列 [力扣 Hot100]

三道高频哈希表应用题:两数之和(利用HashMap快速查找补数)、字母异位词分组(排序后作为键分组)、最长连续序列(通过HashSet去重并仅从序列起点扩展)。核心思想均为借助哈希结构优化查找效率,避免重复计算。同时提及双指针等其他解法思路,体现算法设计中“空间换时间”的典型策略。

2403_87560480的博客 215

LeetCode Hot 100 二叉树专题(三):BST 二叉搜索树与右视图(Java)

本专题主线:三题(98 / 230 / 199)共用两把钥匙——BST 的中序序列严格递增,以及遍历中的"层"与"深度"标记。看懂这两点,三题共用一套模板。 结构约定:每题统一分三部分——①题目分析与解题思路(含易错点辨析);②常见解法(附代码)及讲解;③知识点总结。

2401_88612756的博客 585

LeetCode 3926. 统计有效单词的出现次数【分组循环】

核心思想:用分组循环,一趟遍历字符串,把一个个单词切出来,丢进哈希表统计频次。,先把所有片段拼接成完整文本字符串。,依次返回每个单词在文本里的出现次数。难点:内层循环的判断条件,区分。

2503_92676540的博客 169

力扣第526场周赛心得理解

思路:因为题目要求尽可能求出最小的最大值,而满足要求最小公约数为2,作为题目要求最小的最大值,先去求出它的最大公约数再通过value判断最左边是否大于0,以及value本身是否大于0,而index的位置只能为中间或者最右边,所以最后输出只能是value本身或者在这个基础上加相隔相应距离次数的结果。两个整数,是指将第二个整数的所有十进制数位拼接在第一个整数的所有十进制数位之后。如果不存在这样的数组,返回 -1。4097. 合并整数后的最小值。返回所有合并后得到的整数中的。合并,依此类推,直到将。

目前主攻编程,目标是把屏幕上的红波浪线变成流畅运行的程序♪(^∀^●)ノシ 205

【算法学习笔记】LeetCode 15:三数之和(排序 + 双指针)

使用sort()对数组进行排序。理解排序后双指针的移动原理。使用外层循环固定一个数字。使用左右指针寻找另外两个数字。使用continue和while实现去重。理解的执行逻辑。将三层循环优化为排序 + 双指针,使时间复杂度从 O(n³) 降低到 O(n²)。

aqiu111111的博客 158

LeetCode100 15. 三数之和

本题通过排序+双指针优化三数之和。先对数组排序,外层遍历固定第一个数,内层用左右指针查找另两个数,使三数之和为0。通过剪枝(当前数>0则终止)和去重(跳过重复元素)提升效率。相比暴力或哈希法,该方法时间复杂度为O(n²),空间O(1),更高效优雅。

Shaoxingzong的博客 323

LeetCode hot 100 — 226. 翻转二叉树 | 101. 对称二叉树

自己稀里糊涂写了一版本居然还对了,我觉得我的思想就是很简单,这里就是要交换每一个节点的左右子树,所以套用了一下之前的中序遍历的迭代套路。一直在return False,但是没有给真正的正确答案一个出口(注意递归调用中出口 / 返回值很重要,或者说是最重要的)差一步美满....用的递归的写法,差一点点就满分了,先给出自己最开始写的代码。这道题的本质是对每一个节点执行相同的操作,并且交换哪个节点在先并不重要。你可以运用递归和迭代两种方法解决这个问题吗?,翻转这棵二叉树,并返回其根节点。给你一个二叉树的根节点。

Canmido的博客 133

力扣3无重复字符的最长字串(滑动窗口)

该题使用滑动窗口+哈希集合优化,通过复用Set实现O(n)时间复杂度。若每轮循环都新建HashSet,虽逻辑正确,但需重复插入删除,退化为O(n²),导致超时。原解法利用窗口右移时仅移除左端旧字符、扩展右边界,避免重复操作,实现高效遍历。

Pniubi的博客 229

LeetCode 11 - 20

LeetCode 题库 11 - 20

djhws144的博客 233
上一篇: LeetCode Hot100(68/100)——198. 打家劫舍
下一篇: LeetCode Hot100(70/100)—— 322. 零钱兑换
TracyCoder123
博客等级 码龄8年 1万+粉丝 226原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TracyCoder123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值