反转字符串
const str = 'juejin'
const res = str.split('').reverse().join('')
console.log(res) // nijeuj
回文字符串
正着读和倒着读都一样的字符串
例如:yessey
判断一个字符串是否是回文字符串
function isPalindrome(str) {
// 先反转字符串
const reversedStr = str.split('').reverse().join('')
// 判断反转前后是否相等
return reversedStr === str
}
不难发现:回文字符串还有另一个特性:如果从中间位置“劈开”,那么两边的两个子串在内容上是完全对称的
function isPalindrome(str) {
// 缓存字符串的长度
const len = str.length
// 遍历前半部分,判断和后半部分是否对称
for(let i=0;i<len/2;i++) {
if(str[i]!==str[len-i-1]) {
return false
}
}
return true
}
真题
真题描述:给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串
示例 1: 输入: "aba"
输出: True
示例 2:
输入: "abca"
输出: True
解释: 你可以删除c字符。
注意: 字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。
☆ 关键词:对称性 和 双指针
当两个指针所指字符不同时候,不对称发生,那么就可以试试删掉一个字符的操作:看看区间在 [left+1, right] 或 [left, right-1] 的字符串是否回文
比如说这里我们跳过了 b,[left+1, right] 的区间就是 [2, 2],它对应 c 这个字符,单个字符一定回文。
左右指针内部区间是回文,外部区间也是回文,那么这就是回文字符串了✿✿ヽ(°▽°)ノ✿
const validPalindrome = function (s) {
// 缓存字符串的长度
const len = s.length
// i、j分别为左右指针
let i = 0,
j = len - 1
// 当左右指针均满足对称时,一起向中间前进
while (i < j && s[i] === s[j]) {
i++
j--
}
// 尝试判断跳过左指针元素后字符串是否回文
if (isPalindrome(i + 1, j)) {
return true
}
// 尝试判断跳过右指针元素后字符串是否回文
if (isPalindrome(i, j - 1)) {
return true
}
// 工具方法,用于判断字符串是否回文
function isPalindrome(st, ed) {
while (st < ed) {
if (s[st] !== s[ed]) {
return false
}
st++
ed--
}
return true
}
// 默认返回 false
return false
};
正则表达式
真题描述: 设计一个支持以下两种操作的数据结构:
void addWord(word)
bool search(word)
search(word) 可以搜索文字或正则表达式字符串,字符串只包含字母 . 或 a-z 。
. 可以表示任何一个字母。
示例: addWord("bad")
addWord("dad")
addWord("mad")
search("pad") -> false
search("bad") -> true
search(".ad") -> true
search("b..") -> true
说明:
你可以假设所有单词都是由小写字母 a-z 组成的。
思路分析:
① 添加方法:利用对象存储键值对
② 降低查找复杂度,以字符串长度为key,即相同长度的字符串放在同一个数组
/**
* 构造函数
*/
const WordDictionary = function () {
// 初始化一个对象字面量,承担 Map 的角色
this.words = {}
};
/**
添加字符串的方法
*/
WordDictionary.prototype.addWord = function (word) {
// 若该字符串对应长度的数组已经存在,则只做添加
if (this.words[word.length]) {
this.words[word.length].push(word)
} else {
// 若该字符串对应长度的数组还不存在,则先创建
this.words[word.length] = [word]
}
};
搜索方法:
① 判断输入内容是纯字符串还是正则表达式
② 字符串的话,直接到对应key组找
③ 正则表达式的话,创建正则表达式对象,判断 Map 中相同长度的字符串里,是否存在一个能够与这个正则相匹配
/**
搜索方法
*/
WordDictionary.prototype.search = function (word) {
// 若该字符串长度在 Map 中对应的数组根本不存在,则可判断该字符串不存在
if (!this.words[word.length]) {
return false
}
// 缓存目标字符串的长度
const len = word.length
// 如果字符串中不包含‘.’,那么一定是普通字符串
if (!word.includes('.')) {
// 定位到和目标字符串长度一致的字符串数组,在其中查找是否存在该字符串
return this.words[len].includes(word)
}
// 否则是正则表达式,要先创建正则表达式对象
const reg = new RegExp(word)
// 只要数组中有一个匹配正则表达式的字符串,就返回true
return this.words[len].some((item) => {
return reg.test(item)
})
};
字符串与数字之间的转换问题
题目:请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明: 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−2^31, 2^31 − 1]。如果数值超过这个范围,请返回 INT_MAX (2^31 − 1) 或 INT_MIN (−2^31) 。\
示例 1:
输入: "42"
输出: 42\
示例 2:
输入: " -42"
输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3: 输入: "4193 with words"
输出: 4193
解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例 4: 输入: "words and 987"
输出: 0
解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 因此无法执行有效的转换。
示例 5:
输入: "-91283472332"
输出: -2147483648
解释: 数字 "-91283472332" 超过 32 位有符号整数范围。因此返回 INT_MIN (−2^31) 。
解题思路:
1、 去空格一直找到非空格字符;
2、 识别开头的“+”字符和“-”字符,它能和后面数字组合起来;
3、 见到非整数字符后可以刹车了;
4、 题目明确的数值范围:[−2^31, 2^31 − 1]
// 计算最大值
const max = Math.pow(2,31) - 1
// 计算最小值
const min = -max - 1
// 去空格
let str = ' +10086'
str.trim() // '+10086'
// 用正则表达式匹配
/\s*([-\+]?[0-9]*).*/
\s*,这里的意思就是空格出现0次或多次,都可被匹配到。
()圈住的内容,就是我们要捕获起来额外存储的东西
[]中的匹配符之间是“或”的关系
[0-9]*0-9之间的整数,能匹配到0个或多个就算匹配成功
.这个是任意字符的意思
.*用于字符串尾部匹配非数字的任意字符\
const reg = /\s*([-\+]?[0-9]*).*/
const groups = str.match(reg)
/*
1、 match() 方法是一个在字符串中执行查找匹配的String方法,它返回一个数组,在未匹配到时会返回 null;
2、正则表达式尾部有 g 标志,match()会返回与完整正则表达式匹配的所有结果,但不会返回捕获组;
3、上面正则表达式分析中,只定义了一个捕获组,因从 groups[1] 里拿到我们捕获的结果
*/
完整代码↓
// 入参是一个字符串
const myAtoi = function (str) {
// 编写正则表达式
const reg = /\s*([-\+]?[0-9]*).*/
// 得到捕获组
const groups = str.match(reg)
// 计算最大值
const max = Math.pow(2, 31) - 1
// 计算最小值
const min = -max - 1
// targetNum 用于存储转化出来的数字
let targetNum = 0
// 如果匹配成功
if (groups) {
// 尝试转化捕获到的结构
targetNum = +groups[1]
// 注意,即便成功,也可能出现非数字的情况,比如单一个'+'
if (isNaN(targetNum)) {
// 不能进行有效的转换时,请返回 0
targetNum = 0
}
}
// 卡口判断
if (targetNum > max) {
return max
} else if (targetNum < min) {
return min
}
// 返回转换结果
return targetNum
};