算法刷题-字符串-左旋转字符串

news/2024/11/29 13:28:01/

反转个字符串还有这么多用处?

题目:剑指Offer58-II.左旋转字符串

力扣题目链接

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”

示例 2:
输入: s = “lrloseumgh”, k = 6
输出: “umghlrlose”

限制:
1 <= k < s.length <= 10000

思路

为了让本题更有意义,提升一下本题难度:不能申请额外空间,只能在本串上操作

不能使用额外空间的话,模拟在本串操作要实现左旋转字符串的功能还是有点困难的。

那么我们可以想一下上一题目字符串:花式反转还不够!中讲过,使用整体反转+局部反转就可以实现反转单词顺序的目的。

这道题目也非常类似,依然可以通过局部反转+整体反转 达到左旋转的目的。

具体步骤为:

  1. 反转区间为前n的子串
  2. 反转区间为n到末尾的子串
  3. 反转整个字符串

最后就可以达到左旋n的目的,而不用定义新的字符串,完全在本串上操作。

例如 :示例1中 输入:字符串abcdefg,n=2

如图:

最终得到左旋2个单元的字符串:cdefgab

思路明确之后,那么代码实现就很简单了

C++代码如下:

class Solution {
public:string reverseLeftWords(string s, int n) {reverse(s.begin(), s.begin() + n);reverse(s.begin() + n, s.end());reverse(s.begin(), s.end());return s;}
};

是不是发现这代码也太简单了,哈哈。

总结

此时我们已经反转好多次字符串了,来一起回顾一下吧。

在这篇文章344.反转字符串,第一次讲到反转一个字符串应该怎么做,使用了双指针法。

然后发现541. 反转字符串II,这里开始给反转加上了一些条件,当需要固定规律一段一段去处理字符串的时候,要想想在for循环的表达式上做做文章。

后来在151.翻转字符串里的单词中,要对一句话里的单词顺序进行反转,发现先整体反转再局部反转 是一个很妙的思路。

最后再讲到本题,本题则是先局部反转再 整体反转,与151.翻转字符串里的单词类似,但是也是一种新的思路。

好了,反转字符串一共就介绍到这里,相信大家此时对反转字符串的常见操作已经很了解了。

题外话

一些同学热衷于使用substr,来做这道题。
其实使用substr 和 反转 时间复杂度是一样的 ,都是O(n),但是使用substr申请了额外空间,所以空间复杂度是O(n),而反转方法的空间复杂度是O(1)。

如果想让这套题目有意义,就不要申请额外空间。

其他语言版本

Java:

class Solution {public String reverseLeftWords(String s, int n) {int len=s.length();StringBuilder sb=new StringBuilder(s);reverseString(sb,0,n-1);reverseString(sb,n,len-1);return sb.reverse().toString();}public void reverseString(StringBuilder sb, int start, int end) {while (start < end) {char temp = sb.charAt(start);sb.setCharAt(start, sb.charAt(end));sb.setCharAt(end, temp);start++;end--;}}
}
//解法二:空间复杂度:O(1)。用原始数组来进行反转操作
//思路为:先整个字符串反转,再反转前面的,最后反转后面 n 个
class Solution {public String reverseLeftWords(String s, int n) {char[] chars = s.toCharArray();reverse(chars, 0, chars.length - 1);reverse(chars, 0, chars.length - 1 - n);reverse(chars, chars.length - n, chars.length - 1);return new String(chars);}public void reverse(char[] chars, int left, int right) {while (left < right) {chars[left] ^= chars[right];chars[right] ^= chars[left];chars[left] ^= chars[right];left++;right--;}}

python:

# 方法一:可以使用切片方法
class Solution:def reverseLeftWords(self, s: str, n: int) -> str:return s[n:] + s[0:n]
# 方法二:也可以使用上文描述的方法,有些面试中不允许使用切片,那就使用上文作者提到的方法
class Solution:def reverseLeftWords(self, s: str, n: int) -> str:s = list(s)s[0:n] = list(reversed(s[0:n]))s[n:] = list(reversed(s[n:]))s.reverse()return "".join(s)
# 方法三:如果连reversed也不让使用,那么自己手写一个
class Solution:def reverseLeftWords(self, s: str, n: int) -> str:def reverse_sub(lst, left, right):while left < right:lst[left], lst[right] = lst[right], lst[left]left += 1right -= 1res = list(s)end = len(res) - 1reverse_sub(res, 0, n - 1)reverse_sub(res, n, end)reverse_sub(res, 0, end)return ''.join(res)# 同方法二
# 时间复杂度:O(n)
# 空间复杂度:O(n),python的string为不可变,需要开辟同样大小的list空间来修改
#方法四:考虑不能用切片的情况下,利用模+下标实现
class Solution:def reverseLeftWords(self, s: str, n: int) -> str:new_s = ''for i in range(len(s)):j = (i+n)%len(s)new_s = new_s + s[j]return new_s
# 方法五:另类的切片方法
class Solution:def reverseLeftWords(self, s: str, n: int) -> str:n = len(s)s = s + s return s[k : n+k]# 时间复杂度:O(n)
# 空间复杂度:O(n)

Go:

func reverseLeftWords(s string, n int) string {b := []byte(s)// 1. 反转前n个字符// 2. 反转第n到end字符// 3. 反转整个字符reverse(b, 0, n-1)reverse(b, n, len(b)-1)reverse(b, 0, len(b)-1)return string(b)
}
// 切片是引用传递
func reverse(b []byte, left, right int){for left < right{b[left], b[right] = b[right],b[left]left++right--}
}

JavaScript:

var reverseLeftWords = function(s, n) {const length = s.length;let i = 0;while (i < length - n) {s = s[length - 1] + s;i++;}return s.slice(0, length);
};

版本二(在原字符串上操作):

/*** @param {string} s* @param {number} n* @return {string}*/
var reverseLeftWords = function (s, n) {/** Utils */function reverseWords(strArr, start, end) {let temp;while (start < end) {temp = strArr[start];strArr[start] = strArr[end];strArr[end] = temp;start++;end--;}}/** Main code */let strArr = s.split('');let length = strArr.length;reverseWords(strArr, 0, length - 1);reverseWords(strArr, 0, length - n - 1);reverseWords(strArr, length - n, length - 1);return strArr.join('');
};

TypeScript:

function reverseLeftWords(s: string, n: number): string {/** Utils */function reverseWords(strArr: string[], start: number, end: number): void {let temp: string;while (start < end) {temp = strArr[start];strArr[start] = strArr[end];strArr[end] = temp;start++;end--;}}/** Main code */let strArr: string[] = s.split('');let length: number = strArr.length;reverseWords(strArr, 0, length - 1);reverseWords(strArr, 0, length - n - 1);reverseWords(strArr, length - n, length - 1);return strArr.join('');
};

方法二:

// 拼接两个字符串,截取符合要求的部分
function reverseLeftWords(s: string, n: number): string {return (s+s).slice(n,s.length+n);
};

Swift:

func reverseLeftWords(_ s: String, _ n: Int) -> String {var ch = Array(s)let len = ch.count// 反转区间[0, n - 1]reverseString(&ch, startIndex: 0, endIndex: n - 1)// 反转区间[n, len - 1]reverseString(&ch, startIndex: n, endIndex: len - 1)// 反转区间[0, len - 1],也就是整个字符串反转reverseString(&ch, startIndex: 0, endIndex: len - 1)return String(ch)
}func reverseString(_ s: inout [Character], startIndex: Int, endIndex: Int)  {var start = startIndexvar end = endIndexwhile start < end {(s[start], s[end]) = (s[end], s[start])start += 1end -= 1}
}

PHP

function reverseLeftWords($s, $n) {$this->reverse($s,0,$n-1); //反转区间为前n的子串$this->reverse($s,$n,strlen($s)-1); //反转区间为n到末尾的子串$this->reverse($s,0,strlen($s)-1); //反转整个字符串return $s;
}// 按指定进行翻转 【array、string都可】
function reverse(&$s, $start, $end) {for ($i = $start, $j = $end; $i < $j; $i++, $j--) {$tmp = $s[$i];$s[$i] = $s[$j];$s[$j] = $tmp;}
}

Scala:

object Solution {def reverseLeftWords(s: String, n: Int): String = {var str = s.toCharArray // 转换为Array// abcdefg => ba cdefg reverseString(str, 0, n - 1)// ba cdefg => ba gfedcreverseString(str, n, str.length - 1)// ba gfedc => cdefgabreverseString(str, 0, str.length - 1)// 最终返回,return关键字可以省略new String(str)}// 翻转字符串def reverseString(s: Array[Char], start: Int, end: Int): Unit = {var (left, right) = (start, end)while (left < right) {var tmp = s(left)s(left) = s(right)s(right) = tmpleft += 1right -= 1}}
}

Rust:

impl Solution {pub fn reverse(s: &mut Vec<char>, mut begin: usize, mut end: usize){while begin < end {let temp = s[begin];s[begin] = s[end];s[end] = temp;begin += 1;end -= 1;}}pub fn reverse_left_words(s: String, n: i32) -> String {let len = s.len();let mut s = s.chars().collect::<Vec<char>>();let n = n as usize;Self::reverse(&mut s, 0, n - 1);Self::reverse(&mut s, n, len - 1);Self::reverse(&mut s, 0, len - 1);s.iter().collect::<String>()}
}

http://www.ppmy.cn/news/445003.html

相关文章

Ansible部署和模块应用

Ansible Ansible是一个基于Python开发的配置管理和应用部署工具&#xff0c;现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点&#xff0c;Pubbet和Saltstack能实现的功能&#xff0c;Ansible基本上都可以实现。 Ansible能批量配置、部署、管理上千台主机。比…

Dell inspiron 7580硬件升级_更换电池加内存条移动硬盘

文章目录 前言硬件升级确认硬件型号参数拆机验证硬件更新 附件后记 前言 手上的笔记本[Dell inspiron 7580]用了几年了&#xff0c;还是刚上大学的时候买的&#xff0c;现在感觉这个配置用起来有点吃力了&#xff0c;稍微更新一下配置准备再战两年┭┮﹏┭┮ Light em up, lig…

Dell灵越7000 II系统安装教程

注意&#xff1a;一定要拷贝自己的文件资料&#xff0c;或者进入PE模式拷贝资料。 一、修改BOIS&#xff0c;dell按F2进入BOIS界面 如图所示&#xff1a; 二、下载系统盘&#xff0c;并安装 2.1.下载并安装Dell OS Recovery Tool。 http://www.dell.com/support/h…

全新灵越7000「轻一代」高能合金本限时直降2000元!

有人对高温闷热避之不及&#xff0c;但“恋夏一族”却认为西瓜和美景的夏天简直就是四季中的一番和C位&#xff01;更有生活博主用视频记录了自己的夏日旅行Vlog&#xff0c;看得让人禁不住也想出门玩耍一番。 拍摄Vlog如今已经成为年轻人的一种生活方式&#xff0c;为了产出高…

三星android棒棒糖系统,三星Galaxy S5/S4吃上原生安卓5.0棒棒糖

IT之家讯&#xff0c;不能否认&#xff0c;三星旗舰机一直都是最热门的安卓系列手机&#xff0c;背后也有着为数众多的开发者支持&#xff0c;这显然是一件好事&#xff0c;这样用户在官方升级出来之前就会提前用上新的系统。 那些一直眼馋原生安卓5.0系统的三星S5和三星S4用户…

三星s5如何使用android beam功能,三星Galaxy S5隐藏功能揭秘

三星GALAXY S5在本届MWC上正式发布&#xff0c;虽然在发布会上三星给我们介绍了足够多的新特性让我们心动。但其实一些颇具亮点的功能却并未第一时间展现在我们面前。下面我们就将和大家揭秘三个三星并未在发布会上提到的有趣功能。 Toolbox ▲Toolbox(图片来自于CNET) 针对大屏…

三星星空大赛北京颁奖之旅

很荣幸的有机会参加三星举办的app星空大赛 http://topic.csdn.net/u/20110909/11/8231cec7-331f-4c50-9ceb-1e8b604a1a9c.html http://articles.csdn.net/badasanxingzhuanqu/redianzixun/2011/0825/303621.html 在这次的比赛中&#xff0c;三星提供了Android/Bada/Smart T…

土豪一面展露无疑:三星“打造” Galaxy S5 航站楼

为了促进旗舰机型 Galaxy S5 的销售&#xff0c;三星的营销部门又放出了大招。这次他们看中的是伦敦希思罗机场五号航站楼——欧洲最繁忙的航站楼之一。 从 5 月 19 日开始&#xff0c;希思罗机场五号航站楼将更名两周&#xff0c;被冠以 “Terminal Samsung Galaxy S5″&#…