当前位置: 首页 > news >正文

【编程程序猿艺术】学习记录1:指针向左翻转法的旋转串

【程序猿编程艺术】学习记录1:左旋转字符串之指针翻转法

题目:左旋转字符串
定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部,如把字符串abcdef左旋转2位得到字符串cdefab。

请实现字符串左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n)。空间复杂度为O(n)
思路一、暴力移位法

//暴力移位法
void leftshiftone(char *s, int n)
{
    char t = s[0];
    for(int i = 1;i < n; i++)
        s[i-1] = s[i];
    s[n-1] = t;
}

void leftshift(char *s, int n, int m)
{
    while(m--)
        leftshiftone(s,n);
}

思路二、指针翻转法


參考代码:

#include <iostream>
#include <string>
using namespace std;

void rotate(string &str, int m)
{
    if(str.length() == 0 || m <= 0)
        return;

    int n = str.length();
    //处理m>n的情况
    if(m % n <= 0)
        return;

    int p1 = 0,p2 = m;
    int k = (n - m) - n % m; 
    //交换p1、p2指向的元素,之后移动p1,p2
    while(k --)
    {
        swap(str[p1], str[p2]);
        p1++;
        p2++;
    }

    //处理尾部,r为尾部左移次数
    int r = n - p2;
    while(r--)
    {
        int i = p2;
        while(i > p1)
        {
            swap(str[i], str[i-1]);
            i--;
        }

        p2++;
        p1++;
    }
}

int main()
{
    string ch = "abcdefghijk";
    rotate(ch, 3);
    cout << ch << endl;
    return 0;
}

swap交换函数
思路三、



參考代码:

#include <iostream>
#include <string>
using namespace std;

void rotate(string &str, int m)
{
    if(str.length() == 0 || m < 0)
        return;

    //初始化p1p2
    int p1 = 0,p2 = m;
    int n = str.length();

    //处理m大于n
    if(m%n == 0)
        return;

    //循环至p2到达字符串的末尾
    while(true)
    {
        swap(str[p1],str[p2]);
        p1++;

        if(p2 < n+1)
            p2++;
        else
            break;
    }

    //处理尾部。r为尾部循环左移动的次数
    int r = m - n%m;
    while(r--)
    {
        int i = p1;
        char temp = str[p1];
        while(i < p2)
        {
            str[i] = str[i+1];
            i++;
        }
        str[p2] = temp;
    }
}

思路4、上述都是如果m<n,我们如今考虑m为负数和m大于n的可能
參考代码:

#include <iostream>
#include <string>
using namespace std;

//const int positiveMod(m,n) = (m % n + n) % n; //无效
//#define positiveMod(m,n) ((m) % (n) + (n)) % (n) //宏定义切记这里不能加上;号
inline int positiveMod(int m, int n) //内联
{
    return ((m) % (n) + (n)) % (n);
}
//左旋转字符串str,假设m为负数。则有右旋转
void rotate(string &str, int m)
{
    if(str.length() == 0)
        return;

    //初始化
    int n = str.length();
    int p1 = 0,p2 = m;

    //处理m大于n以及m为负数的情况,positiveMod
    m = positiveMod(m,n);
    if(m == 0)
        return;

    int round;

    //p2当前所指和之后的m-1个字母共m个字母,就能够和p2前面的m个字母交换
    while(p2 + m - 1 < n)
    {
        round = m;
        while(round--)
        {
            swap(str[p1], str[p2]);
            p1++;
            p2++;
        }
    }

    //剩下的不足m个字母一个一个交换
    int r = n - p2;
    while(r--)
    {
        int i = p2;
        while(i > p1)
        {
            swap(str[i], str[i-1]);
            i--;
        }
        p2++;
        p1++;
    }
}

//測试
int main()
{
    cout << ((-15)%7 + 7)%7 << endl;
    cout << (-15)%7 << endl;
    string ch = "abcdefg";
    int len = ch.length();

    for(int m = -2*len; m <= len * 2; m++)
    {
        //因为传给rotate的是string的引用。所以每次调用都用一个新字符
        string s = "abcdefg";
        rotate(s,m);
        cout << positiveMod(m,len) << ": " << s << endl;
    }
    return 0;
}

思路5、递归转换法



參考代码:

#include <iostream>
using namespace std;

void rotate(string &str, int n, int m, int head, int tail, bool flag)
{
    //n表示待处理的字符串长度。m为待处理部分的旋转长度
    //head:待处理部分的头指针 tail待处理部分的尾指针
    //flag = true表示左旋,否则右旋

    //返回条件
    if(head == tail || m <= 0)
        return;

    if(flag == true)
    {
        int p1 = head;
        int p2 = head + m;

        int k = (n-m) - n % m; //p1,p2移动距离,向右

        for(int i = 0; i < k; i++,p1++,p2++)
            swap(str[p1], str[p2]);


        //结束左旋进入右旋
        rotate(str, n-k, n %m, p1, tail, false);
    }
    else
    {
        int p1 = tail;
        int p2 = tail - m;

        //p1,p2移动距离
        int k = (n-m)-n%m;

        for(int i = 0; i < k; i++, p1--,p2--)
            swap(str[p1],str[p2]);

        rotate(str,n-k,n % m, head, p1, true);
    }
}

int main()
{
    int i = 3;
    string str = "abcdefghijk";
    int len = str.length();
    rotate(str,len, i%len ,0,len-1,true);
    cout << str.c_str() << endl;//转化成字符数组的形式输出
    return 0;
}

版权声明:本文博主原创文章,博客,未经同意不得转载。

相关文章:

  • Windows XP 死期将至 微软终于伸援手了
  • xen的实时迁移(四)
  • 递归3--棋盘分割
  • android网络开源框架volley(五岁以下儿童)——volley一些细节
  • 查看自己的电脑的内存扩充-最大
  • MySQL错误Another MySQL daemon already running with the same unix socket.v
  • CSS制作响应式正方形及其应用
  • css中attribute selector及pseudo class
  • “考虑不全面”导致的大问题!!!
  • [Linux]于Mac在配置Linuxserver安装Nginx+PHP
  • Multimodal —— 看图说话(Image Caption)任务的论文笔记(二)引入attention机制
  • NFS服务配置固定端口
  • 别再用 MongoDB 了!
  • 第十章:异常处理
  • export Jar from eclipse (总结)
  • ES6指北【2】—— 箭头函数
  • axios 和 cookie 的那些事
  • eclipse(luna)创建web工程
  • ES10 特性的完整指南
  • Javascript设计模式学习之Observer(观察者)模式
  • jQuery(一)
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • MySQL QA
  • nginx 配置多 域名 + 多 https
  • TypeScript实现数据结构(一)栈,队列,链表
  • Vue小说阅读器(仿追书神器)
  • windows-nginx-https-本地配置
  • 浮动相关
  • 离散点最小(凸)包围边界查找
  • 聊一聊前端的监控
  • 入门到放弃node系列之Hello Word篇
  • 在Unity中实现一个简单的消息管理器
  • 正则表达式小结
  • #git 撤消对文件的更改
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #vue3 实现前端下载excel文件模板功能
  • (1)bark-ml
  • (33)STM32——485实验笔记
  • (39)STM32——FLASH闪存
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (Matlab)使用竞争神经网络实现数据聚类
  • (八)Flask之app.route装饰器函数的参数
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (一) storm的集群安装与配置
  • (已解决)什么是vue导航守卫
  • (转)socket Aio demo
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • **python多态
  • .apk 成为历史!
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .Net下使用 Geb.Video.FFMPEG 操作视频文件
  • .net中调用windows performance记录性能信息