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

news2024/12/27 19:25:35

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

题目:剑指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:

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.coloradmin.cn/o/658061.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++算法:单源最短路径Dijkstra

文章目录 前言一、Dijkstra算法思想二、算法实现1、建立图2、代码实现 总结 前言 如果你有一份北京地图&#xff0c;想从中关村走到三元桥&#xff0c;那么怎样能找出实现这一目的的最短路径呢?一种可能的方法就是将这两点之间所有的路线都找出来&#xff0c;然后求出每条路线…

openSUSE项目近日宣布openSUSE Leap 15.5的发布和全面供应

openSUSE项目近日宣布openSUSE Leap 15.5的发布和全面供应&#xff0c;该版本是openSUSE变体的最新稳定版本&#xff0c;针对那些希望为其个人电脑提供基于SUSE Linux Enterprise 15的经过良好测试的操作系统的用户。 openSUSE Leap 15.5是在openSUSE Leap 15.4的一年后推出的&…

Vue中如何进行音频可视化与音频频谱展示

Vue中如何进行音频可视化与音频频谱展示 随着音频应用程序的不断发展&#xff0c;音频可视化和音频频谱展示成为了重要的功能。在Vue应用程序中实现音频可视化和音频频谱展示可以帮助用户更好地了解音频文件的内容和特征。本文将介绍如何在Vue应用程序中实现音频可视化和音频频…

Opensearch基本介绍

OpenSearch 是一个社区驱动的开源搜索和分析套件&#xff0c;开发人员使用该套件来摄取、搜索、可视化和分析数据。 OpenSearch 由数据存储和搜索引擎 (OpenSearch)、可视化和用户界面 (OpenSearch Dashboards) 以及服务器端数据收集器 (Data Prepper) 组成。 用户可以使用一系…

把数字中国,建立在行业感知的底座上

5月23日&#xff0c;国家互联网信息办公室发布了《数字中国发展报告&#xff08;2022年&#xff09;》。报告显示&#xff0c;2022年中国数字经济规模达到50.2万亿元&#xff0c;占国内生产总值比重提升至41.5%&#xff0c;总量居世界第二。如今数字中国最主要的发展挑战&#…

MIFARE - 1

2一般说明 飞利浦根据ISO/IEC 14443A开发了用于非接触式智能卡的MIFAREMF1 IC S50。通信层&#xff08;MIFARERF接口&#xff09;符合ISO/IEC 14443A标准的第2部分和第3部分。安全层采用经过现场验证的CRYPTO1流密码&#xff0c;用于MIFAREClassic系列的安全数据交换。 MIFARE…

GPT中的temperature参数不是用在对话的而是用在调用OPEN API过程中的

前言 自从吴恩达OPENAI《ChatGPT 提示工程》放出后,各个层面反响热列。很多人看到了temperature这个参数,都以为在对话中或者说对话的末尾放上一个temperature=0-2的值就可以达到让GPT极大的发挥出自我创造能力、甚至写文章天马行空。 笔者这边觉得有义务指出这种用法是完全…

OpenAI ChatGPT 使用示例(程序员)

1.编程应用 1.1. 生成例子代码(Coding Generation) ChatGPT帮助我们生产我们需要的例子代码。而且准确率很高。即使你不懂某一种语言也没关系&#xff0c;一定程度上较低了程序员的的门槛。 我有三组数据&#xff0c;第一组是星期一到星期五&#xff0c;第二组是这一天的具体…

第七十八天学习记录:高等数学:微分方程(宋浩板书)

微分方程&#xff08;Differential equation&#xff09;是描述自然现象中变量之间关系的数学语言。它是以函数、导数、微分等数学概念为基础的方程&#xff0c;揭示了自然现象中变量之间的内在联系。微分方程在物理学、工程学、生物学、经济学、统计学等各领域都有广泛的应用。…

C++线程库(2)

C线程库&#xff08;2&#xff09; 线程同步互斥锁条件变量与互斥锁的搭配使用举例1举例2举例3 线程同步 在C线程库&#xff08;1&#xff09;的博客中说了互斥量只能解决多个线程访问共享资源的问题&#xff0c;但是很明显没有次序感&#xff0c;而线程安全就是不同线程访问资…

最短路径算法-迪杰斯特拉(Dijkstra)算法(记录最短路径和距离)

原理&#xff1a; Dijkstra算法是解决**单源最短路径**问题的**贪心算法** 它先求出长度最短的一条路径&#xff0c;再参照该最短路径求出长度次短的一条路径 直到求出从源点到其他各个顶点的最短路径。 首先假定源点为u&#xff0c;顶点集合V被划分为两部分&#xff1a;集合…

chatgpt赋能python:Python字符串去除多余空格

Python字符串去除多余空格 随着Python在各个领域的应用越来越广泛&#xff0c;很多工程师都会遇到字符串去除多余空格的需求。而Python提供了简单的方法来解决这个问题&#xff0c;本文将详细介绍这些方法。 介绍 在Python中&#xff0c;字符串是很常见的数据类型&#xff0…

Linux环境下的工具(yum,gdb,vim)

一&#xff0c;yum yum其实是linux环境下的一种应用商店&#xff0c;主要用centos等版本。它也有三板斧&#xff1a;yum list,yum remove,yum install。当然不是说他只有这三个命令&#xff0c;还有yum search等等。在这直说以上三个。 yum list其实是查看你所能安装的软件包…

puppet 入门详解 超详细!!!

目录 一、puppet概述 二、Puppet的工作模式是什么&#xff1f; 三、Puppet的适用场景是什么&#xff1f; 四、原理 &#xff08;一&#xff09;工作模型 &#xff08;二&#xff09;工作流程 &#xff08;三&#xff09;使用模型 1、单机使用模型 2、master/agent 模型 &…

Vue中如何进行自动化部署与持续集成(CI/CD)

Vue中如何进行自动化部署与持续集成&#xff08;CI/CD&#xff09; 随着云计算和容器技术的广泛应用&#xff0c;自动化部署和持续集成&#xff08;CI/CD&#xff09;已经成为现代软件开发过程中必不可少的环节。Vue作为一款流行的前端框架&#xff0c;也可以使用自动化部署和…

解决:闹钟设置的自定义歌曲响铃时不会播放仅震动【Apple Music】【iOS】

文章目录 1、问题描述2、解决策略3、Q&A4、感受5、Tips 1、问题描述 自带铃声和震动脑瓜子嗡嗡的&#xff0c;幸好有apple music&#xff0c;在闹钟中可以轻松地选择你放入资料库中的任意一首音乐作为铃声。 奇怪的是&#xff0c;闹钟响起&#xff0c;仅震动&#xff0c;没…

chatgpt赋能python:Python怎么过滤非数字

Python怎么过滤非数字 在实际编程过程中&#xff0c;我们常常遇到要对一些数据进行处理&#xff0c;其中经常需要过滤掉非数字的数据&#xff0c;以保证程序能够正常运行。在Python中&#xff0c;若要过滤非数字&#xff0c;可以采用如下几种方法。 方法一&#xff1a;使用正…

chatgpt赋能python:Python中如何输入以0开头的数字?

Python中如何输入以0开头的数字&#xff1f; 在Python编程中&#xff0c;可能会遇到需要输入以0开头的数字的情况。然而&#xff0c;当我们尝试在Python shell或代码中输入以0开头的数字时&#xff0c;我们会发现Python会自动将其转换为八进制格式。 为什么Python会将以0开头…

使用MDK-ARM(KEIL V5)创建一个工程(有图有文字)

使用keil v5创建工程是一个比较复杂的过程&#xff0c;还希望读者能够耐下心来&#xff0c;过于浮躁会使创建过程出错&#xff0c;导致编译器无法编译等等许多问题。 言归正传&#xff0c;我们接下来开始说明创建过程&#xff0c;说明过程以图片为主&#xff0c;文字为辅&…

谷粒商城第四天-前端基础

目录 一、前言 二、学习的内容 一、ES6新语法 1.1 var与let 1.2 const 1.3 解构表达式的使用 1.4 字符串Api的使用 1.5 函数优化 1.6 箭头函数 1.7 对象优化 1.8 map和reduce 1.9 promise异步编排 1.10 模块化&#xff08;export和import的使用&#xff09;…