344.反转字符串
题目
求解
题目要求不给数组分配额外的空间,将数组第i
个元素和倒数第i
个交换位置即可
代码
var reverseString = function(s) { // 不能给数组分配额外的空间 // 前面和后面的交换位置 let left = 0, right = s.length-1; while(left<right){ [s[left],s[right]] = [s[right],s[left]]; left++; right--; } return s; };
541.反转字符串Ⅱ
题目
求解
当需要固定规律一段一段去处理字符串的时候,要想想如何在for循环的表达式上做做文章。
找规律:
-
arrayS.length < k
时,反转所有字符,下标从0
到arrayS.length-1
-
k<= array.length < 2*k
时,反转前k个字符,下标从0
到k-1
-
arrayS.length > 2*k
时,先反转前k个字符再检测第2k+1个元素后面的字符满足上述哪种条件,当有多段字符需要反转时,两段相邻的字符串开始下标相差为
2*k
因此设计for
循环,循环体中下标更新为i += 2*k
,即for(let i=0;i<arrayS.length;i+=2*k)
,对每段字符串进行检测并反转
使用双指针法进行部分反转,i
即表示需要反转的开始位置,接下来确定结束位置right
-
不足k个元素时,
arrayS.length - i < k
时,right = arrayS.length - 1
-
有k个元素可以反转,
right = i + k - 1
代码
var reverseStr = function(s, k) { let arrayS = s.split(""); for(let i = 0;i<s.length;i += 2*k){ // 如果有的话 前k个进行反转 // 如果剩余少于k,反转剩余所有 right = s.length - i < k ? s.length -1 : i + k -1 // 如果剩余>=k,反转前k个 let left = i, right = s.length - i < k ? s.length -1 : i + k -1; while(left<right){ [arrayS[left],arrayS[right]] = [arrayS[right],arrayS[left]]; left++; right--; } } return arrayS.join("") };
剑指offer05.替换空格
题目
求解
很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。因为从前向后的话,每次移动都需要后移后面所有的元素,时间复杂度为O(n^2)。
-
检测空格出现的次数
-
使用快慢指针更新数组,即从后往前填充数组
-
fast
指向新数组的尾部,slow
指向旧数组的尾部 -
当
slow
指向空格时arrayS[slow] ===' '
,fast
指向的地方需要添加三个元素arrayS[fast--] = '0'; arrayS[fast--] = '2'; array[fast--] = '%';
-
当
slow
指向的不是空格,fast
记录这个字符arrayS[fast--] = arrayS[slow--];
-
代码
var replaceSpace = function(s) { // 字符串转为数组 let arrayS = s.split(""); let spaceNum = 0; // 字符串中的空格变为%20,每有一个空格,数组长度需要+2 // 计算空格的数量 for(let i=0;i<s.length;i++){ if(arrayS[i] === ' ') spaceNum++; } // 一个指向原数组末尾,一个指向新数组末尾 let left = s.length - 1, right = s.length + 2 * spaceNum -1; // 替换空格 并后移相应元素 // 如果出现空格,新数组分别加入% 2 0, 没出现空格,新数组拷贝旧数组元素 while(left>=0){ if(arrayS[left] === ' '){ arrayS[right--] = '0'; arrayS[right--] = '2'; arrayS[right--] = '%'; left--; }else{ arrayS[right--] = arrayS[left--]; } } return arrayS.join(""); };
151. 反转字符串中的单词
题目
求解
-
将字符串转为数组
let strArr = s.split("");
-
首先需要去掉多余的空格,包括前导空格,尾随空格和单词间多余1个的空格。
-
删除数组中的元素,使用双指针法,快指针遍历数组,慢指针记录新的数组
-
检测前导空格,
strArr[fast] === ' ' && fast === 0
-
检测单词中多余的空格,
strArr[fast] === ' ' && strArr[fast] === strArr[fast-1]
-
删除前导、多余空格,
strArr[slow++] = strArr[fast++]
-
检测尾随空格,
strArr[slow] === ' '
-
删除尾随空格,
strArr.length = slow-1;
-
-
对整个字符串进行反转
-
对每个单词进行反转,检测单词
-
双指针法找到单词,
i
去遍历字符串,start
记录单词第一个字母的位置 -
单词最后一个字母的确定,当
strArr[i] === ' '
时,反转下标start
到i-1
部分,并更新start = i+1
-
由于字符串整体反转后,不存在尾随空格,最后一个单词不能用上述方法确定,最后一个单词的尾部为
i === strArr.length
-
代码
var reverseWords = function(s) { let strArr = s.split(""); // 首先需要去掉可能存在的多余空格,包括前导空格,尾随空格和单词间多于1个的空格 removeExtraSpaces(strArr); // 先反转整个字符串,再反转单独的单词 reverseWord(strArr,0,strArr.length-1); // start记录单词开始的地方,i去遍历字符串,遇到空格反转前面的单词。最后一个单词后没有空格,单独处理 let start = 0; for(let i = 0;i<=strArr.length;i++){ if(strArr[i] === ' ' || i === strArr.length){ reverseWord(strArr,start,i-1); start = i+1; } } // 移除多余的空格 双指针法 // 快指针遍历,慢指针为新数组坐标 function removeExtraSpaces(strArr){ let fast = 0, slow = 0; while(fast<strArr.length){ // 删除开头的空格,和多余的空格 // 即fast === 0, strArr[fast] === ' ' 和 strArr[fast] === strArr[fast-1] === ' ' if(strArr[fast] === ' ' &&(fast === 0 || strArr[fast-1] === ' ')){ fast++; }else{ strArr[slow++] = strArr[fast++]; } } // 末尾的空格 strArr.length = strArr[slow-1] === ' '? slow-1:slow; } // 单个单词内部反转 function reverseWord(strArr,start,end){ let left = start,right = end; while(left<right){ [strArr[left],strArr[right]] = [strArr[right],strArr[left]]; left++; right--; } } return strArr.join(""); };
剑指offer58.左旋转字符串
题目
求解
方法1:先反转前n个字符,再反转第n个字符后的所有字符,再反转整体
方法2:将第n个字符后的字符整体前移(将最后一个插到最前面)
需要调整len-n
次,每次将最后一个字符调整到最前面,其中let len = s.length;
,采用字符串拼接的形式。let len = s.length;
需要事先记录,因为在拼接的过程中,字符串的长度会发生变化
代码
// 方法1 var reverseLeftWords = function(s, n) { // 先反转前n个,再反转n个后面的,再反转整体 function reverse(strArr,start,end){ let left = start, right = end; while(left<right){ [strArr[left],strArr[right]] = [strArr[right],strArr[left]]; left++; right--; } } let sArr = s.split(""); reverse(sArr,0,n-1); reverse(sArr,n,sArr.length-1); reverse(sArr,0,sArr.length-1); return sArr.join(""); };
// 方法2 var reverseLeftWords = function(s, n) { let len = s.length; let i = 0; while(i<len-n){ // 将最后一个字符提到最前面,采用字符串拼接的形式 s = s[len-1] + s; i++; } return s.slice(0,len); };