字符串左旋详解(超详细)~

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

字符串左旋详解(超详细)~,开发语言,算法,c语言



Hello,大家好呀,今天给大家讲解一下这道字符串左旋题型。

题目链接:

牛客网:JZ58 左旋转字符串

题目描述:

描述:
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列 S ,请你把其循环左移 K 位后的序列输出。例如,字符序列 S = ”abcXYZdef” , 要求输出循环左移 3 位后的结果,即 “XYZdefabc”。
数据范围:输入的字符串长度满足 0≤len≤100, 0<=n<=100
进阶:空间复杂度O(n),时间复杂度O(n)
示例1
输入: “acXYZdef”,3
返回值:“XYZdefabc”

示例2
输入: “aab”,10
返回值:“aba”

题目注意事项:

字符串左旋详解(超详细)~,开发语言,算法,c语言


需要注意的是,本题那个函数的形参部分是char *str指的是用指针的的形式接收main中所定义str数组首元素的地址。

比如我们给大家看一下main函数的代码是怎么进行调用函数LeftRotateString的。

int main() {
	
    char str[] = "ABCD";
    LeftRotateString(str, 1);
	printf("%s\n", str);
	
    return 0;
}

而形参部分的n指的是该字符串需要左移的个数。比方说LeftRotateString函数实参部分我传的是1,那么n的值就为1。

当我们把该字符串已经翻转好所传的函数实参n的次数,那我们直接就返回字符串就行,无需打印。

例如:

return str;

当我们明白题目的打印输出方式,那我们就可以开始解题啦!
字符串左旋详解(超详细)~,开发语言,算法,c语言

首先呢,在解题之前,我们先把字符串的长度先求出来。

那我们该怎么求字符串长度呢?我们可以先定义一个len的变量,然后再用strlen函数计算它的长度。
又因为函数形参部分*str是接收了main函数中数组str首元素的地址,那么strlen函数是从数组的首元素地址开始计算,直到遇到‘\0’就结束

那么这个代码我们可以这么写

int len=strlen(str);

当我们算出len字符串长度后,我们就进入正式进入解题环节。
字符串左旋详解(超详细)~,开发语言,算法,c语言

解题思路分析:

解法一

思路分析:

首先呢,我们可以采用1个字符1个字符地左旋,比如把最左边的那个字符左旋转到最后面那个字符,也就是左旋到’\0’前面的那一个字符,然后根据所要旋转的次数,逐一进行左旋,直到我们把所有字符都左旋完毕后,就返回str字符串到main函数那儿。

但我们如何控制所要移动的次数呢?
比方说,我们原字符串为“ABCD”,我们要左移5次,最终它左旋后的结果是什么呢?

我们可以通过动图观看它的移动轨迹~
字符串左旋详解(超详细)~,开发语言,算法,c语言

最终旋转之后的结果是这样的:
字符串左旋详解(超详细)~,开发语言,算法,c语言

从图中,我们可以看到把字符串"ABCD"左旋5次之后的结果跟左旋一次之后的结果是一样的。
并且,虽然它的字符为4个字符,但是我可以挪动的次数可以超过4个字符次。

那我们如果如何知道自己挪动的次数呢?

事实上,我们可以定义一个变量times,然后用形参n%lens,比如我用main函数中传过去的是5,那么n=5,接下来用strlen计算出该字符串长度len=4,然后5%4=1,也就是说只用挪动一次就能得到左旋一次的那个字符串结果出来。


那如果我们是一次一次地挪,我们代码该怎么写呢?

比方说,我们可以先写个外层的for循环,然后在循环体内,我们可以定义变量tmp,并对数组名str进行解引用操作,然后把str所指向对象的值赋给变量tmp
然后我们定一个变量j,令j=0,然我们在外层的for循环体内再写一个for循环,然后随着j的值增加,然后我们还要加上j<lens-1的循环条件
可能有人会有疑问为什么循环是j<lens-1,而不是j<len呢?

我们可以看一下下面的动图所示:
字符串左旋详解(超详细)~,开发语言,算法,c语言

从该动图中,我们可以看到,在循环体内,数组后面的元素会覆盖掉前面的元素,如果我们写成代码形式的话。
就是这样:

str[j]=str[j+1]

当j的值等于len-1的话,会跳出内层的for循环,然后到那个时候,j的值等于len-1,然后我们再把tmp的值赋给str[j]。
也就是:

str[j]=tmp;

当我们理解它的代码逻辑之后,我们就能进行整个代码实现了。

代码实现:
char* LeftRotateString(char* str, int n) {
    int lens = strlen(str);
    if (lens == 0)
        return "";
	int times = n % lens;
	for (int i = 0; i < times; i++) {
		char tmp = *str;
		int j = 0;
		for (; j < lens - 1; j++) {
			str[j] = str[j + 1];
		}
			str[j] = tmp;
	}
    return str;
}

当然有人会有疑问为什么要加上这两行代码?

 if (lens == 0)
      return "";

我们不妨看一下牛客网运行用例是否正确。
字符串左旋详解(超详细)~,开发语言,算法,c语言

从图中,我们很明显就看出如果main函数中传入的是空的字符串,那么我们strlen计算lens的长度,它就为0。但是当lens=0作为除数的话,这显然是不符合数学逻辑的,因此当strlen计算出len=0时,应立即返回str这个值。就不能让下面那条语句执行,不然程序就会出错。

而当我们把那两行代码加上去后,它那个评分系统才会全部通过所有用例。
字符串左旋详解(超详细)~,开发语言,算法,c语言

虽然这种一个字符一个字符这样移方法比较简单,但是执行次数会比较多,有点繁琐,因此我们接下来会展示其他思路。

解法二

思路分析1:

那么我们讲的第二种方法就是拷贝法拼接法,拼接法的实质也就是借助C语言的库函数来完成
那我们就先介绍拷贝函数strcpy。
字符串左旋详解(超详细)~,开发语言,算法,c语言
从函数官网中,我们可以看出strcpy函数中的第一个参数是填目标的字符串,而第二个参数是填从原字符串的某个位置开始拷贝的。
实际上,strcpy函数用法是从原字符串的某个位置开始拷贝,直到遇到null字符就停止拷贝,也就是遇到’\0’就停止拷贝。
字符串左旋详解(超详细)~,开发语言,算法,c语言
另外,我们再讲一下strncpy函数,strncpy这个库函数和strcpy函数很类似,但其实它们两个函数还是有所区别的,因为它的第三个函数参数要写那个数字个数。

那比如这个原字符串为“ABCD”,我们要移动3次。那这个代码我们用刚刚所讲的那两个库函数该怎么实现呢?

字符串左旋详解(超详细)~,开发语言,算法,c语言

首先呢,还是老样子,我们还是要先用strlen函数计算那个字符串长度,并且还要保证那个所传的str字符串不是空字符,接着再n%len,计算出所要左旋的次数。也就是我们要先加上这四行代码。

 int lens = strlen(str);
  if (lens == 0) 
  return str; 
  int times = n % lens;

接着,我们还要定义一个tmp的数组来存储那个字符。
字符串左旋详解(超详细)~,开发语言,算法,c语言
根据题目要求,输入的字符串长度要满足0≤len≤100
因此我们最好就这样定义那个tmp数组。

char tmp[101

然后我们可以再用动图分析一下这个两个库函数实现的逻辑:
字符串左旋详解(超详细)~,开发语言,算法,c语言

从动图中,我们也能得知,该函数strcpy可以先将从str+times地址所指向的字符到‘\0’之前的字符拷贝到变量tmp中。
那么代码我们可以这么写:

strcpy(tmp,str+times);

接着,我们看动图,它把"BCD"字符串直接拷到srt那儿,那这个代码我们又该怎么写呢?

我们可以用strncpy函数来进行拷贝,然后在strncpy函数内的我们可以怎么写呢。由于刚刚我们已经把字符A已经拷贝到变量tmp,所以tmp首元素的地址所指向的对象就是字符A,但我们不能直接拷到tmp首元素的那个位置那里,因为这样会把字符A给覆盖掉了。那我们那个目标位置要放到字符A的后面,也就是用tmp首元素地址+(字符串长度lens-左旋的次数times),然后起始位置我们就可以写成src了,因为数组名是数组首元素的地址。然后最后一个参数size_t num就直接写成左旋的次数times就OK啦!因此代码可以写成这样子。

strncpy(tmp+(times-lens),str,times);

这样我们就成功把左旋后的字符串全部拷贝给tmp数组里面,但是题目要求我们返回的是str字符串,因此我们还要把tmp数组里面的字符串直接拷贝到str数组内,那么这时,我们直接用strcpy这个函数进行拷贝就行了,并且它们的起始位置和目标位置分别为tmp和str数组首元素的位置。因此根据分析,那个代码就可以这么写

strcpy(str,tmp);
代码实现1:

在分析完这些代码逻辑后,最终我们代码可以这么写。
字符串左旋详解(超详细)~,开发语言,算法,c语言

char* LeftRotateString(char* str, int n) {

    int lens = strlen(str);
    if (lens == 0)
        return str;
    int times = n % lens;
    char tmp[101];
    strcpy(tmp,str+times);
    strncpy(tmp+(lens-times),str,times);
    strcpy(str,tmp);
    return str;
}


字符串左旋详解(超详细)~,开发语言,算法,c语言
虽然这个代码可以成功运行,但我认为这个程序还是有待完善的。

那我们该怎么完善呢?接下来我来给大家分析一下。

思路分析2:

再讲解这个思路分析2的代码实现之前,我们再给大家介绍一个库函数strncat,首先呢,我们先看一下函数的参数有什么呢?
字符串左旋详解(超详细)~,开发语言,算法,c语言
从图中,我们可以看出这个strncat这个函数的函数参数看似跟strncpy这个函数参数一样,并且都是遇到’\0’就终止了。
但是这两个函数本质上还是有区别的。我们来给大家解释一下为什么。比方说,我们还是跟上面一样,先加上这行代码

strcpy(tmp,str+times);

然后呢,我们这时候如果是用strncat函数进行拼接的话,它的第二个参数目标位置是可以直接写成tmp数组名的形式。其他两个参数都不变。也就是这种形式。

strncat(tmp,str,times);

有人会有疑问,为什么可以这么写呢?

因为它这个strncat函数是不会把前面已经拷贝进tmp的字符给覆盖掉,而是会在之前strcpy拷贝后的那个字符后面再进行拼接,并且如果这么写,显然是比之前写的那个strncat拼接函数要方便。

而当我们拼接完那个函数后,我们就直接用拷贝函数strcpy操作就行,也就是:

strcpy(str,tmp);
代码实现2:

当我们分析完这个strncat函数用法后,我们就可以直接写出它的代码出来了。

char* LeftRotateString(char* str, int n) {

    int lens = strlen(str);
    if (lens == 0)
        return str;
    int times = n % lens;
    char tmp[101];
    strcpy(tmp,str+times);
    strncat(tmp,str,times);
    strcpy(str,tmp);
    return str;
}

运行结果也是照样正确
字符串左旋详解(超详细)~,开发语言,算法,c语言
虽然这个解法代码思路比较简洁易懂,但是呢,仅仅用两个库函数就做出来,未免会有点耍技巧。假如我们到时参加技术笔试、面试,面试官如果说不能用这个库函数的方法解这类题,那我们该如何改进呢?

那么接下来,我们就给大家介绍另外一种解题方法。

解法3

思路分析:

首先呢,我们可以采用局部翻转的方法来对字符串进行左旋的操作。
比方说,我们举个例子,我们main函数传的字符串是"ABCDEF",旋转次数为2的话。那左旋后的字符串是不是”CDEFAB"?
可能很多人对局部翻转的概念还是很懵,那我们直接上动图!
字符串左旋详解(超详细)~,开发语言,算法,c语言
从该动图中,我们发现当左旋的次数n=2时,就是先对前两个字符翻转,接下来就对后面那四个字符进行翻转,最后再进行整体进行翻转。最终我们就能把左旋n次的字符串求出来。

那这个代码我们该怎么实现呢?

首先呢,还是老样子,我们依然要把字符串times的次数和lens的长度求出来。也就是要加上这四行代码:

int lens = strlen(str);
if (lens == 0)
	return str;
int times = n % lens;

接下来,我们要创建一个Reverse的函数,那里面的参数我们该传什么呢?事实上,由于我们是通过数组下标来进行局部翻转字符的,并且从上面动图分析,就是先将以下标为0~times-1的元素来翻转,然后再将下标time-lens-1的元素进行翻转,最后再将下标为0-lens-1的元素进行整体翻转。那么我们就可以在写出这三行调用函数的代码出来,也就是

Reverse(str,0,times-1);
Reverse(str,times,lens-1);
Reverse(str,0,lens-1);

那么接下来在Reverse这个函数内部我们应该怎么写呢?
首先呢,在形参部分我们先用指针的形式来接收字符str,又因为在Reverse函数内要对数组局部再进行翻转,因此呢,剩下那两个参数我们可以写成int left,int right的形式,方便到时进行数组翻转操作。
那么形参部分就是写成

void Reverse(char*str,int left,int right)

又因为我们本质上是要实现所传进来字符的交换,因此在Reverse函数内部我们可以这么写,==我们可以先定义一个while循环,在循环体内,首先创建一个变量tmp,然后把*(str+left)赋给tmp,相当于str跳过left个元素,接着再对它进行解引用操作,就能访问它所指向的对象出来 ,接着我们再把*(str+right)所指向对象的值赋给*(str+left),最后再将tmp的值赋给*(str+right)。那么我们就能写下这三行代码出来!

char tmp=*(str+left);
*(str+left)=*(str+right);
*(str+right)=tmp;

而又因为left的值要比right的值要小,因此如果要把所传进来的字符进行全部翻转,我们就要写上这两行代码:

right--;
left++;

那么循环条件我们可以通过上面那两行代码推导出来,也就是while(left<right)。让数组left和right下标的值逐渐向中间的元素的值靠拢,直到left=right,不符合while循环条件,便跳出while循环,从而就能实现这些字符地交换。

最终我们代码可以写成这样:
字符串左旋详解(超详细)~,开发语言,算法,c语言

代码实现:
void Reverse(char*str,int left,int right){
    while(left<right){
        char tmp=*(str+left);
        *(str+left)=*(str+right);
        *(str+right)=tmp;
        left++;
        right--;
    }
}
 
 
char* LeftRotateString(char* str, int n) {
 
    int lens = strlen(str);
    if (lens == 0)
        return str;
    int times = n % lens;
    Reverse(str,0,times-1);
    Reverse(str,times,lens-1);
    Reverse(str,0,lens-1);
 
    return str;
}

我们不妨看一下运行结果。
字符串左旋详解(超详细)~,开发语言,算法,c语言

这里是显示是通过所有用例的,因此这个代码逻辑是没问题的。

好了,今天题目的分享到这里就结束啦,如果大家对本题有更多的解题思路,或者博主讲得不太好的地方,欢迎大家在评论区交流或者私信博主。

写到最后,希望大家能给博主一个三连支持一下

字符串左旋详解(超详细)~,开发语言,算法,c语言


谢谢!!!!!
文章来源地址https://www.toymoban.com/news/detail-716895.html

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

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

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

相关文章

  • (字符串 ) 剑指 Offer 58 - II. 左旋转字符串 ——【Leetcode每日一题】

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

    2024年02月08日
    浏览(45)
  • c语言进阶部分详解(详细解析字符串常用函数,并进行模拟实现(下))

    上篇文章介绍了一些常用的字符串函数,大家可以跳转过去浏览一下:c语言进阶部分详解(详细解析字符串常用函数,并进行模拟实现(上))_总之就是非常唔姆的博客-CSDN博客 今天接着来介绍一些:  目录 一.字符串查找 1.strstr() 1.1示例 1.2注意事项: 1.3模拟实现  2.

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

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

    2024年02月06日
    浏览(47)
  • LeetCode:剑指 Offer 58 - II. 左旋转字符串

    🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀 算法专栏: 👉🏻123 题目描述 :字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串\\\"abcdefg\\\"和数字2,该函数将返回左旋

    2024年02月02日
    浏览(46)
  • 【代码随想录 | Leetcode | 第十一天】字符串 | 反转字符串 | 反转字符串 II | 替换空格 | 反转字符串中的单词 | 左旋转字符串

    欢迎来到小K的Leetcode|代码随想录|专题化专栏,今天将为大家带来字符串~反转字符串 | 反转字符串 II | 替换空格 | 反转字符串中的单词 | 左旋转字符串的分享 ✨ ✨题目链接点这里 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要

    2024年02月15日
    浏览(51)
  • 第8天-代码随想录刷题训练-字符串● 344.反转字符串 ● 541. 反转字符串II ● 剑指Offer 05.替换空格 ● 151.翻转字符串里的单词 ● 剑指Offer58-II.左旋转字符串

    LeetCode链接 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 swap常见的两种交换形式 常见的值交换 通过位运算 LeetCode链接 给定一个

    2024年02月04日
    浏览(61)
  • C语言字符串详解

    目录 一、字符串的概念 二、占用内存的情况 三、字符串的初始化 四、字符串与指针  五、字符串的结尾标志 六、字符串常用的库函数 1、获取字符串的长度(strlen) 举个例子 运行效果 自己实现一个 strlen 函数 运行效果 2、字符串复制或赋值(strcpy)  自己实现一个 strcp

    2024年01月23日
    浏览(40)
  • C语言字符函数和字符串函数详解

           Hello, 大家好,我是一代,今天给大家带来有关字符函数和字符串函数的有关知识        所属专栏:C语言        创作不易,望得到各位佬们的互三呦 在C语言中有一些函数是专门为字符设计的,这些函数的使用都需要包含一个头文件ctype.h 如:(注:以下函数原型都

    2024年03月20日
    浏览(51)
  • c语言中字符串详解

    C 语言中没有字符串这种数据类型,可以通过char型数组来替代 ; 注意: C 语言中,字符串一定是一个char型数组,但char型数组未必是字符串; 在C语言的char型数组中,数字0(和字符‘\\0’等价)结尾的char数组就是一个字符串,但如果 char 型数组没有以数字0结尾,那么就不是

    2023年04月08日
    浏览(32)
  • 字符串函数(C语言详解)

    字符串是一串连续的且以\\0结尾的字符 注意: 1.以第一种形式初始化字符串时,计算机会自动在字符串末尾加上\\0,所以在给数组申请内存空间时,需要多申请一个字节的内存来存放\\0 2.第二种形式是 常量字符串 ,是 不可以被修改 的 3.第三种形式是字符数组,末尾没有\\0,输

    2024年03月17日
    浏览(45)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包