字符串的左旋问题解析

1.实现一个函数,可以左旋字符串中的k个字符。
AABCD左旋一个字符得到ABCDA
AABCD左旋两个字符得到BCDAA

第一种方法:

思路:先将一个字符串左移一位,可以使用一层for循环来实现,
然后每次都可以调用这层循环,调用移位的次数,还有就是,
循环次数如果大于字符串的长度,会重复执行一些无用的
操作,所以给step模上字符串的长度,就可以产生一个小于
字符串长度的数字。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

void str_shift(char *str,int len, int step)
{
    int i = 0;
    int j = 0;
    char tmp = 0;
    step %= len;//step为0到(len - 1)的一个数字,提高了移位时的效率
    assert(str);
    assert(len > 1);
    for (j = 0; j < step; j++)//外层循环实现左移step位
    {
        tmp = str[0];
        for (i = 0; i < len - 1; i++)//内层循环实现了左移一次
        {

            str[i] = str[i+1];
        }
        str[i] = tmp;
    }
}


int main()
{
    char msg[] = "ABCD1234";
    int k = 0;
    printf("Please Enter:>");
    scanf("%d",&k);
    printf("before      : %s\n",msg);
    str_shift(msg,strlen(msg), k);
    printf("shift_after : %s\n",msg);
    system("pause");
    return 0;
}

这里写图片描述

第二种方法:
思路:将一个字符串从它要移位的位置分为两个部分,
(例如:字符串:ABCD1234 要移3位 则将其分为 ABC D1234),
然后将它的左右两边的子字符串各自逆置(CBA 4321D),
然后将逆置后的结果(D1234ABC)再进行整体逆置, 这个结果就是
将原字符串左移3位后的结果。
其实就是将前后两部分各自逆置了两次,然而却把前面的一部分旋转到了这个字符串的尾部。
这里写图片描述

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

void swap(char *start, char *end)//交换两个字符
{
    *start ^= *end;
    *end ^= *start;
    *start ^= *end;
}

void reverse(char *start, char *end)
{
    assert(start);
    assert(end);
    while (start < end)//将字符串逆置
    {
        swap(start,end);
        start++,end--;
    }
}

void str_shift(char *str,int len, int step)
{
    char *middle = NULL;
    step %= len;//使得移位的步数小于字符串的长度
    middle = str + step - 1;//middle将字符串分为两部分
    assert(str);
    assert(len > 1);
    assert(step > 0);
    reverse(str,middle);//将分开的左半部分逆置
    reverse(middle +1, str + len - 1);//将分开的右半部分逆置
    reverse(str,str + len -1);//将整体逆置
}

int main()
{
    char msg[] = "ABCD1234";
    int k = 0;
    printf("Please Enter:>");
    scanf("%d",&k);
    printf("before      : %s\n",msg);
    str_shift(msg,strlen(msg), k);
    printf("shift_after : %s\n",msg);
    system("pause");
    return 0;
}

第三种方法:
思路:使用双重字符串(例如:ABCDABCD),如果需要左旋1位,
则让字符串的首地址加上1,从此处截取字符串长度的字符(BCDA),
则这个结果就是左旋一位后的结果,但是这种方法不适合长度特别大的
字符串。

这里写图片描述

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

//------双重字符串
//1234------1 2341234---左旋一位----(str+1,str+len-1)
                     //左旋2位-----(str +2,str+ 2 +len -1)
                    // 左旋step位----(str + k,str + step -1)

void str_shift(char *str,int len, int step)
{
    char *newstr = NULL;
    assert(str);
    assert(len > 1);//检查len是否大于1
    assert(step > 0 );//检查要左旋的位数是否大于0
    step %= len;               
    newstr = (char *)malloc(sizeof(char) * len * 2 +1);//开辟双重字符串的空间
    strcpy(newstr,str);//将原字符串拷贝到新的字符串中
    strcat(newstr,str);//将原字符串连接到新字符串中,使之产生双重字符串
    strncpy(str,newstr + step,len);//从左旋的位数开始,复制字符串长度个字符
    free(newstr);//在堆上开辟的空间需要自行释放
    newstr = NULL;
}

int main()
{
    char msg[] = "ABCD1234";
    int k = 0;
    printf("Please Enter:>");
    scanf("%d",&k);
    printf("before      : %s\n",msg);
    str_shift(msg,strlen(msg), k);
    printf("shift_after : %s\n",msg);
    system("pause");
    return 0;
}

这里写图片描述

2.判断一个字符串是否为另外一个字符串旋转之后的字符串。
例如:给定s1 = AABCD和s2 = BCDAA,返回1,给定s1=abcd和s2=ACBD,返回0.

AABCD左旋一个字符得到ABCDA
AABCD左旋两个字符得到BCDAA

AABCD右旋一个字符得到DAABC
AABCD右旋两个字符得到CDAAB

分析:可以在第一道题的思路上向下延伸:
要使得一个字符串是另一个字符串旋转之后得到的字符串,首先
两个字符串长度必须一样长,不然一定不会是旋转之后得到的字符串,
如果一个字符串是另一个字符串经过旋转可以得到的,那么这个字符串
一定是它双重字符串的一个字串。
例如:(ABCD)与(CDAB)——双重字符串(AB**CDAB**CD),
由此可以看出它是它的双重字符串的一个子串。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

int  is_sub_str(char *str,char *arr)
{
    char *newstr = NULL;
    int len = strlen(str);
    assert(str);
    assert(arr);
    assert(len > 0);//检查len是否大于0
    if (strlen(str) == strlen(arr))
    {
        newstr = (char *)malloc(sizeof(char) * len * 2 +1);//开辟双重字符串的空间
        strcpy(newstr,str);//将原字符串拷贝到新的字符串中
        strcat(newstr,str);//将原字符串连接到新字符串中,使之产生双重字符串
        if (strstr(newstr,arr) == NULL)//如果在双重字符串中没有找到arr这个字符串
        {                             //则返回0
            return 0;                     
        }
        return 1;//如果在双重字符串中找到了arr字符串,则返回1
    free(newstr);//在堆上开辟的空间需要自行释放
    newstr = NULL;
   }
    return 0;
}

int main()
{
    char msg[] = "ABCD1234";
    char str[] = "CD1234AB";
    printf("is sub str : %d",is_sub_str(msg,str));//是---返回1    不是----返回0
    system("pause");
    return 0;
}

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值