var reverseString = function(s) {
let len = s.length
let mid = Math.floor((s.length - 1) / 2) //向下取整 如果长度是奇数,那么mid是最中间的结点 如果长度是偶数,那么mid是中间两个结点的前一个
console.log(len,mid)
for(let i=0;i<=mid;i++){
[s[i],s[len - 1 - i]] = [s[len - 1 - i],s[i]]
}
};
var reverseString = function(s) {
let len = s.length
if(len==0||len==1) return s
let left = 0,right = len - 1
while(left<right){
[s[left],s[right]] = [s[right],s[left]]
left++
right--
}
};
var reverseStr = function(s, k) {
let arr = s.split("")
const helper = (a,b) =>{
//反转实现的具体功能
let left = a,right = b
while(left<right){
[arr[left],arr[right]] = [arr[right],arr[left]]
left++
right--
}
}
let len = s.length
const reduce = (start,end) =>{
if(start>end) return
if(end - start < k){
helper(start,end)
return
}
if(end - start < 2*k){
helper(start,start+k-1)
return
}
//翻转
helper(start,start+k-1)
//继续递归
reduce(start+2*k,len-1)
}
reduce(0,len - 1)
return arr.join("")
};
var reverseStr = function(s, k) {
const helper = (start,end) =>{
while(start<end){
[arr[start],arr[end]] = [arr[end],arr[start]]
start++
end--
}
}
let len = s.length
let arr = s.split("")
for(let i=0;i<len;i+=2*k){
if(i+k<=len){
helper(i,i+k-1)
}else{
helper(i,i+len-1)
}
}
return arr.join("")
};
var replaceSpace = function(s) {
//js中字符串不支持修改
let str = s.split(" ").join("%20")
return str
}
var replaceSpace = function(s) {
//js中字符串不支持修改
return s.replaceAll(" ","%20")
}
var replaceSpace = function(s) {
//js中字符串不支持修改
let str = ''
for(let i=0;i<s.length;i++){
str+=s[i]==" "?"%20":s[i]
}
return str
}
参考
var replaceSpace = function(s) {
//js中字符串不支持修改
//原地修改 不借助任何js内置函数
let arr = s.split("")
let oldLen = arr.length
let spaceCount = 0 //用来记录空格的个数
for(let item of arr){
if(item==" ") spaceCount++
}
let newLen = oldLen + spaceCount*2 //注意这里不是乘以3 因为原来的空格占一个位置,所以这里用来替换空格 每个加2
let i = oldLen - 1 , j = newLen - 1
//思路是 每次将字符串往后移动
for(;i<j;i--,j--){
if(arr[i]!==" "){
arr[j] = arr[i]
}else{
arr[j] = '0'
arr[j-1] = '2'
arr[j-2] = '%'
j-=2 //这里虽然j移动了三个位置,for循环里面j会减一
}
}
return arr.join("")
}
这是按照代码随想录的写法,主要锻炼思维能力
var reverseWords = function(s) {
//思路:将字符串转数组 然后去掉多余的空格 然后翻转
let arr = Array.from(s)
//去掉多余的空格
const moveExtraSpace = arr =>{
//使用快慢指针
let slow = 0, fast = 0
while(fast<arr.length){
//当fast指向的位置是空格,且是第一个位置 那么fast向后移动 或者 别的情况出现空格表示一个单词的结束 我们需要保留一个空格 连续出现两个空格 就将多余的消除掉
if(arr[fast]==" "&&(fast==0||arr[fast-1]==" ")){
fast++
}else{
arr[slow++] = arr[fast++]
}
}
//while循环结束之后 fast指向arr的最后一个位置
//去掉末尾的空格 如果arr最后几个位置都是空格 那么最后可能的情况是slow不动了(此时指向空格的下一个位置) fast一直移动直到跳出while => 这里要判断arr[slow-1]
arr.length = arr[slow-1] == ' '?slow-1:slow
}
const reverseArr = (arr,start,end) =>{
let left = start,right = end
while(left<right){
[arr[left],arr[right]] = [arr[right],arr[left]]
left++
right--
}
}
moveExtraSpace(arr)
reverseArr(arr,0,arr.length-1)
//对每个单词进行翻转
let start = 0
for(let i=0;i<=arr.length;i++){
if(arr[i]==" " || i == arr.length){ //这里当i指向最后一个位置的下一个位置的时候,需要对最后一个单词进行翻转
//对每个单词进行翻转 当i指向空的时候,表示一个单词的结束 我们让start指向i的下一个位置 指向新单词的开始
reverseArr(arr,start,i-1)
start = i + 1
}
}
return arr.join("")
};
split(/\s+/) 是 JavaScript 中用于对字符串进行分割的方法,其中 /\s+/ 是一个正则表达式,表示匹配一个或多个空格字符(包括空格、制表符和换行符)。
例如,如果有一个字符串 “hello world”,执行该字符串的 split(/\s+/) 方法会将其分割成两个部分:[“hello”, “world”]。也就是说,字符串中的空格被用作分隔符,返回一个数组,数组中的元素为被分割后的各个部分。
var reverseWords = function(s) {
return s.trim().split(/\s+/).reverse().join(" ")
};
var reverseWords = function(s) {
//自己的思路
s = s.trim()
let newStr = ""
for(let i = 0;i<s.length;i++){
if(s[i]==" "&&s[i-1]==" "){ //s已经去掉了首尾的空格 那么i=0的时候就不会出现 空格
continue//进入下一层循环
}else{
newStr+=s[i]
}
}
return newStr.split(" ").reverse().join(" ")
};
var reverseLeftWords = function(s, n) {
if(n>=s.length) return s
let arr = s.split("")
let cur = s.length
let count = 0
let i = 0
while(count<n){
arr[cur] = arr[i]
cur++
i++
count++
}
return arr.splice(n).join("")
};
var reverseLeftWords = function(s, n) {
//翻转字符串
const reverse = (str,left,right) =>{
let arr = str.split("")
while(left<right){
[arr[left],arr[right]] = [arr[right],arr[left]]
left++
right--
}
return arr.join("")
}
//先两部分局部翻转 然后整体反转
s = reverse(s,0,n-1)
s = reverse(s,n,s.length-1)
return reverse(s,0,s.length-1)
};
haystack是文本串(设其长度是n),needle是模式串(设其长度是m)
时间复杂度是O(mn)
var strStr = function(haystack, needle) {
let i = 0 , j = 0
while(i<haystack.length&&j<needle.length){
if(haystack[i]==needle[j]){
i++
j++
//如果j++之后已经溢出了,那么说明needle已经判断完了
if(j==needle.length) return i - j
continue //进入下一层循环
}else{
j = 0
}
}
return -1
};
var strStr = function(haystack, needle) {
return haystack.indexOf(needle)
};
时间复杂度是O(n+m)
next数组保留原始的数值 实现方法一
var strStr = function(haystack, needle) {
//kmp算法 ①要知道最长公共前后缀的长度;②求next数组,利用next数组进行跳转,当模式串不匹配的时候,去查找相应的next数组,next数组 下标为i的地方 表示i之前的(包含i)的字符串的最长公共前后缀的长度;next数组有两种表示方式,第一种 整体减一 第二种 保留原数
//第一种,next整体保留原样
if(needle.length==0) return 0
//根据模式串来求next数组
const getNext = str =>{ //这种方式 前缀必须得有第一个元素 后缀必须得有最后一个元素 i指向当前(包括i这个位置)这样一个串的最大公共前后缀的长度
//也可以将求next数组的过程中,next[i]放的是指针i之前(包括i的)这样一个字串
let next = []
let j = 0 //j 指向字符串前缀的末尾
next.push(j)
for(let i=1;i<str.length;i++){
//由于i在后缀上 j在前缀上 当i j两个位置的元素不匹配的时候,j需要next数组来找j-1前面的串的最大前后缀的公共长度
while(j>0&&str[i]!==str[j]){
j = next[j-1] //j进行回退
}
if(str[i]==str[j]){
j++ //i就不用加了 for里面
}
next[i] = j
}
return next
}
//进行模式串的匹配
let j = 0 //指向模式串
//对文本串进行遍历
let next = getNext(needle)
for(let i=0;i<haystack.length;i++){
while(j>0&&haystack[i]!==needle[j]){
//这种情况j要根据next数据进行回退
j = next[j-1]
}
if(haystack[i]==needle[j]){
j++
}
if(j==needle.length){
return i-needle.length+1
}
}
return -1
};
var strStr = function(haystack, needle) {
//实现方法二
if(needle.length==0) return 0
const getNext = str =>{
let next = []
let j = -1 //整体的next数组中的值 减一
next.push(j)
for(let i=1;i<str.length;i++){
while(j>=0&&str[i]!==str[j+1]){
j = next[j]
}
if(str[i]==str[j+1]){
j++
}
next.push(j)
}
return next
}
let next = getNext(needle)
let j = -1
for(let i=0;i<haystack.length;i++){
while(j>=0&&haystack[i]!==needle[j+1]){
j = next[j]
}
if(haystack[i]==needle[j+1]){
j++
}
if(j==needle.length-1){
return i-needle.length+1
}
}
return -1
};
var repeatedSubstringPattern = function(s) {
//滑动窗口
let mid = Math.ceil((s.length-1)/2)
for(let i=1;i<=mid;i++){
let temp = s.slice(0,i) //temp作为窗口
//这个窗口从 s的 i这个位置开始进行比较
let j = 0 //指向temp的起始位置
let cur = i //cur指向s的i的位置
while(cur<s.length){
if(s[cur]==temp[j]){
cur++
j++
}else{ //continue 会进入下一趟的while循环 break跳出
break //进入下一层for循环
}
if(cur<s.length&&j>=temp.length){ //只有当s还没有比较完成
j = 0
}
}
//s temp比较完成最后一个 cur++ j++
if(cur==s.length&&j==temp.length) return true
}
return false
};
时间复杂度是O(n) 求next数组
空间复杂度是O(n) next的大小
var repeatedSubstringPattern = function(s) {
//使用kmp算法 求next数组 整个字符串s的最长公共前后缀的长度
//比如字符串 ababababab
// 那么最长的前缀字符串是 abababab
//最长的后缀字符串是 abababab 这样我们的重复的字串是 ab 整个串s的长度对ab长度进行整除 正好可以整除
const getNext = str =>{
let j = 0
let next = []
next.push(j)
for(let i=1;i<str.length;i++){
while(j>0&&str[i]!==str[j]){
j = next[j-1]
}
if(str[i]==str[j]){
j++
}
next[i] = j
}
return next
}
let next = getNext(s)
//判断s的公共前后缀长度是否是0
if(next[s.length-1]!==0&&(s.length%(s.length-next[s.length-1]))==0) return true
return false
};
var repeatedSubstringPattern = function(s) {
//移动匹配 s+s之后,去掉头尾得到t 那么t中一定有s这个串 为啥要去头尾呢?避免头尾的影响
let t = s + s
t = t.slice(1,2*s.length - 1)
return t.indexOf(s) == -1?false:true //这里要注意:使用库函数判断是否包含一个串 时间复杂度是O(m+n) 如果要暴力的话,时间复杂度O(mn)
};