一天一大 leet(恢复空格)难度:中等-Day20200709
时间:2022-07-25
本文章向大家介绍一天一大 leet(恢复空格)难度:中等-Day20200709,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目:
哦,不!你不小心把一个长篇文章中的空格、标点都删掉了,并且大写也弄成了小写。像句子"I reset the computer. It still didn’t boot!"已经变成了"iresetthecomputeritstilldidntboot"。在处理标点符号和大小写之前,你得先把它断成词语。当然了,你有一本厚厚的词典 dictionary,不过,有些词没在词典里。假设文章用 sentence 表示,设计一个算法,把文章断开,要求未识别的字符最少,返回未识别的字符数。
注意: 本题相对原题稍作改动,只需返回未识别的字符数
示例
输入:
dictionary = ["looked","just","like","her","brother"]
sentence = "jesslookedjustliketimherbrother"
输出:7
解释:断句后为"jess looked just like tim her brother",共7个未识别字符
提示
- 0 <= len(sentence) <= 1000
- dictionary 中总字符数不超过 150000。
- 你可以认为 dictionary 和 sentence 中只包含小写字母。
抛砖引玉
思路:
- 首先要把字符串所有可能存在的切分规则枚举出来 对 sentence 进行双层遍历
- 另外,每次单词被分割出来之后,需要判断这个单词是否在 wordDict 中
- 存在,继续向后枚举
- 不存在,存放本轮枚举的结果+截取的不匹配的字符长度
逻辑:
- 存放本轮枚举的结果:
- 设传入的 sentence 的长为 len,那么声明一个数组 dp,dp[len] 来表示 sentence 中最少不匹配数
- sentence 为空时,不匹配长度为 0,即:dp[0] = 0
- 参照上面存储逻辑,sentence 长 len,sentence[len]做本轮匹配的终点,依次向前移动指针给其添加字母:
- 如果 dictionary 包含分割出的字符,那不满足的值应该和该片段前一个存储的值相同
- 如果不包含,那说明本次截取的值不满足,记录分割的长度+该片段前一个存储的值
直到添加到字母首位。
注意:每次 i 增加时,其其实值应该为 dp[i-1] + x
- dictionary 包含 sentence 的第 i 个字符则,x 为 0
- 不包含则为 1
/**
* @param {string[]} dictionary
* @param {string} sentence
* @return {number}
*/
var respace = function (dictionary, sentence) {
let len = sentence.length,
dp = new Array(len + 1).fill(0)
for (let i = 1; i <= len; i++) {
dp[i] = dp[i - 1] + (dictionary.includes(sentence[i - 1]) ? 0 : 1)
for (let j = i - 1; j >= 0; j--) {
let word = sentence.substring(j, i)
if (dictionary.includes(word)) {
dp[i] = Math.min(dp[i], dp[j])
} else {
dp[i] = Math.min(dp[i], dp[j] + i - j)
}
}
}
return dp[len]
}
其他解法
哈希判断包含
上面判断分割的字符是否包含在 dictionary 中用了 includes includes 内部还有一次轮询,可以使用哈希来替代,优化时间
哈希方法可以用 set,map,object 实现
/**
* @param {string[]} dictionary
* @param {string} sentence
* @return {number}
*/
var respace = function (dictionary, sentence) {
let len = sentence.length,
dp = new Array(len + 1).fill(0),
map = new Map()
// 字典生成哈希
dictionary.forEach((i) => map.set(i))
for (let i = 1; i <= len; i++) {
dp[i] = dp[i - 1] + (map.has(sentence[i - 1]) ? 0 : 1)
for (let j = i - 1; j >= 0; j--) {
if (map.has(sentence.substring(j, i))) {
dp[i] = Math.min(dp[i], dp[j])
} else {
dp[i] = Math.min(dp[i], dp[j] + i - j)
}
}
}
return dp[len]
}
指定分割长度
- 存储不匹配结果的逻辑不变
- 按照字典 dictionary 中单词的长度对 sentence,优化切分规则
/**
* @param {string[]} dictionary
* @param {string} sentence
* @return {number}
*/
var respace = function (dictionary, sentence) {
let len = sentence.length,
dp = new Array(len + 1).fill(0)
for (let i = 1; i <= len; i++) {
// 初始值
dp[i] = dp[i - 1] + (dictionary.includes(sentence[i - 1]) ? 0 : 1)
// 遍历字典,分割字符
for (let j = 0; j < dictionary.length; j++) {
let item = dictionary[j],
itemLen = item.length,
strStart = i - ditemLen
// 小于字段字符长度不分割
if (i < itemLen) continue
if (sentence.substring(strStart, i) === item) {
// 存在则取该位置不匹配的最小值
dp[i] = Math.min(dp[strStart], dp[i])
}
}
}
return dp[len]
}
优化:
- 使用按字段分割的方式,就可以省略 dp 的初始化了
- 不会再涉及向前查询是查到 undefind 的问题
则优化后为:
/**
* @param {string[]} dictionary
* @param {string} sentence
* @return {number}
*/
var respace = function (dictionary, sentence) {
let dp = [0],
len = sentence.length
for (let i = 1; i <= len; i++) {
dp[i] = dp[i - 1] + (dictionary.includes(sentence[i - 1]) ? 0 : 1)
for (let j = 0; j < dictionary.length; j++) {
let item = dictionary[j]
if (sentence.substring(i - item.length, i) === item) {
dp[i] = Math.min(dp[i], dp[i - item.length])
}
}
}
return dp[dp.length - 1]
}
- 持续不断地推荐儿童不宜视频背后,YouTube是这样训练AI的
- 人工智能会导致大量失业,你怕吗
- 机器人产业链分析-中国机器人产业的发展机遇和挑战
- 如何与深度学习服务器优雅的交互?
- 比特币大跌又反弹30%,区块链技术与企业级有着怎样的关系?
- 十个实用MySQL函数
- 使用Apprenda和R分析应用程序工作负载数据
- 实现微信朋友圈所有动态点赞的自动化用例
- 后台设计的一些总结
- 2017年区块链当中的黑客大事件
- 5个云安全解决方案的注意事项
- 深入剖析ASP.NET的编译原理之二:预编译(Precompilation)
- 深入剖析ASP.NET的编译原理之二:预编译(Precompilation)
- Nodejs学习笔记(十六)--- Pomelo介绍&入门
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- go-zero 微服务框架介绍
- redis-cli 未找到命令的一个解决方式
- 【每日一题】42. Trapping Rain Water
- iframe跨域安全
- Efficiently traversing InnoDB B+Trees with the page directory (9.利用页目录实现对B+树的高效遍历)
- C语言 | 每日基础(37)
- 《求求大厂给个Offer》Map面试题
- C语言 | 每日基础(40)
- kubernete编排技术七:secret
- springcloud+eureka整合seata-tcc模式
- 【源码】手把手教你用Python实现Vivado和ModelSim仿真自动化
- typescript基础篇(7):类型检查机制
- 说来惭愧,我被ulimit摔了一跤...
- Kubectl 备忘录
- 手把手教你移动端AI应用开发(二)——将AI模型集成到安卓应用中