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

这篇具有很好参考价值的文章主要介绍了算法刷题-字符串-左旋转字符串。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

题目:剑指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 += 1
                right -= 1
        
        res = list(s)
        end = len(res) - 1
        reverse_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 = startIndex
    var end = endIndex
    while start < end {
        (s[start], s[end]) = (s[end], s[start])
        start += 1
        end -= 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 gfedc
    reverseString(str, n, str.length - 1)
    // ba gfedc => cdefgab
    reverseString(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) = tmp
      left += 1
      right -= 1
    }
  }
}

Rust:文章来源地址https://www.toymoban.com/news/detail-491037.html

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>()
    }
}

到了这里,关于算法刷题-字符串-左旋转字符串的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【leetcode 力扣刷题】字符串翻转合集(全部反转///部分反转)

    题目链接:344. 反转字符串 题目内容: 题目中重点强调了必须 原地修改 输入数组,即不能新建一个数组来完成字符串的反转。我们注意到: 原来下标为0的,反转后是size - 1【原来下标是size - 1的,反转后是0】; 原来下标是1的,反转后是size - 2【原来下标是size -2的,反转后

    2024年02月11日
    浏览(29)
  • 【JavaScript数据结构与算法】字符串类(反转字符串中的单词)

    个人简介 👀 个人主页: 前端杂货铺 🙋‍♂️ 学习方向: 主攻前端方向,也会涉及到服务端(Node.js) 📃 个人状态: 在校大学生一枚,已拿多个前端 offer(秋招) 🚀 未来打算: 为中国的工业软件事业效力 n 年 🥇 推荐学习:🍍前端面试宝典 🍉Vue2 🍋Vue3 🍓Vue2/3项目

    2023年04月09日
    浏览(74)
  • 【每日挠头算法题(1)】——旋转字符串|亲密字符串

    点我直达终点~ 前提:如果s串和goal串长度不等,则goal串不可能是s串旋转得来,直接返回false; 通过观察,可以发现每旋转一次,第一个字符就会出现在最后一个字符的位置处,其余字符均往前挪动一个位置。 所以我们首先将第一个字符保存,然后挪动其他字符,再将保存的

    2024年02月08日
    浏览(30)
  • 字符串左旋详解(超详细)~

    Hello,大家好呀,今天给大家讲解一下这道字符串左旋题型。 牛客网:JZ58 左旋转字符串 描述: 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列 S ,请你把其循环左移 K 位后的序列输出

    2024年02月08日
    浏览(26)
  • 算法通关村第十二关——字符串反转问题解析

    字符串反转是关于字符串算法里的重要问题,虽然不是太难,但需要考虑到一些边界问题。本篇文章就对几道字符串反转题目进行分析。 力扣344题,编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间,

    2024年02月10日
    浏览(33)
  • 算法刷题-字符串-重复的子字符串

    KMP算法还能干这个 力扣题目链接 给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。 示例 1: 输入: “abab” 输出: True 解释: 可由子字符串 “ab” 重复两次构成。 示例 2: 输入: “aba” 输出: False 示

    2024年02月09日
    浏览(32)
  • 算法刷题-字符串-翻转字符串里的单词

    综合考察字符串操作的好题。 力扣题目链接 给定一个字符串,逐个翻转字符串中的每个单词。 示例 1: 输入: “the sky is blue” 输出: “blue is sky the” 示例 2: 输入: \\\" hello world! \\\" 输出: “world! hello” 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不

    2024年02月09日
    浏览(83)
  • 数据结构与算法之字符串: Leetcode 557. 反转字符串中的单词 III (Typescript版)

    翻转字符串中的单词 III https://leetcode.cn/problems/reverse-words-in-a-string-iii/ 描述 给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 示例 1: 示例 2: 提示: 1 = s.length = 5 * 1 0 4 10^4 1 0 4 s 包含可打印的 ASCII 字符。 s 不包含任何开头或

    2024年02月01日
    浏览(62)
  • (字符串 ) 剑指 Offer 58 - II. 左旋转字符串 ——【Leetcode每日一题】

    难度:简单 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串\\\"abcdefg\\\"和数字2,该函数将返回左旋转两位得到的结果\\\"cdefgab\\\"。 示例 1: 输入: s = “abcdefg”, k = 2 输出: “cdefgab” 示例 2:

    2024年02月08日
    浏览(29)
  • 剑指Offer--05替换空格&&58左旋字符串

    题目是这样的 意思是将字符串s中的空格替换为字符串\\\"%20\\\",如果只是替换一个字符还好,可以在原数组直接替换,但是是将空格替换为字符串,所以再在原数组上替换,原数组原内容会被覆盖,且长度大小不够,所以此时要动态开辟一个字符数组,这个数组开多大?考虑最坏

    2024年02月06日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包