杂题之循环移动字符串

1.问题:一个m个字符的字符串,‘循环’ 向左或向右移动n(n <= m)位,求移动后的字符串。例如abcdefg 左循环移动3位 -> defgabc, 又循环移动三位 -> efgabcd.

2.实现方法很多,最直接但是效率很低的方法是挨个移动字符元素,类似移动数组。这里介绍一个技巧来实现, 以循环左移n位为例

  1).首先翻转前n位,此时你可以伸出右手,手心对着你自己,假设此时从无名指到大拇指标号为1,2,3,4,5;然后翻转你的右手,让手心对外,则此时为5,4,3,2,1。翻转前n位字符串的过程与此类似。

    那么程序中这个过程如何实现呢,很简单,就是第一位和最后以为对换,第二位和倒数第二位对换,依次类推,实现代码如下:

static void
swap(char &a, char &b)
{
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}

static void
move(char *str, int head, int tail)
{
    if (str == NULL || strlen(str) < 2)
    {
        return;
    }

    for (; head < tail; head++, tail--)
    {
        swap(*(str + head), *(str + tail));
    }
}

  2).将n+1到m位翻转,过程与上边类似。当然这两个翻转执行顺序没有先后的区别。

  3).将字符串整体翻转后,便得到循环左移后的字符串。

  循环右移的过程于此类似。

3.下面贴出可以选择循环左移和右移的代码(move.c),读者可以参考这理解:

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

static void
swap(char &a, char &b)
{
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}

static void
move(char *str, int head, int tail)
{
    if (str == NULL || strlen(str) < 2)
    {
        return;
    }

    for (; head < tail; head++, tail--)
    {
        swap(*(str + head), *(str + tail));
    }
}

int
main(int argc, char *argv[])
{
    char str[100] = { 0 };
    int movenum;
    char direc;

    while(1)
    {
        printf("Enter a string And move direction(L or R) And a move num\n");
        if (scanf("%s %c %d", str, &direc, &movenum) == 3)
        {
            if (movenum < 0 || movenum > strlen(str))
            {
                printf("error\n");
                continue;
            }

            printf("Before Move: %s \n", str);

            if (‘R‘ == direc)
            {
                //the sequence of two move op can be changed
                move(str, strlen(str) - movenum, strlen(str) - 1);
                move(str, 0, strlen(str) - movenum - 1);
            }
            else if (‘L‘ == direc)
            {
                //the sequence of two move op can be changed
                move(str, 0, movenum - 1);
                move(str, movenum, strlen(str) - 1);
            }
            else
            {
                continue;
            }
            move(str, 0, strlen(str) - 1);    

            printf("After  Move: %s \n", str);
        }
        else
        {
            break;
        }
    }

    return 0;
}

  编译命令: g++ -g -o move move.c;,运行: ./move

  部分运行结果:

  

  当让只是简单的示例程序,如果代码出错,欢迎指正, 同时若有更好的方法,希望不吝赐教。

  

时间: 2024-08-26 00:57:49

杂题之循环移动字符串的相关文章

hdu 3641 数论 二分求符合条件的最小值数学杂题

http://acm.hdu.edu.cn/showproblem.php?pid=3641 学到: 1.二分求符合条件的最小值 /*==================================================== 二分查找符合条件的最小值 ======================================================*/ ll solve() { __int64 low = 0, high = INF, mid ; while(low <=

循环移动字符串

这个问题的意思就是给定两个字符串s1和s2,判断s2是否包含在s1循环移位得到的字符串中. 这个题的最简单的一种思路就是对s1进行循环穷举,对于得到的每种情况,都进行判断s2是否包含在其中. 不过如果s1的字符串很长,那么穷举的时间复杂度是相当高的.因此可以换一种思路. 新的解决办法相当的巧妙,假设我们在s1字符串前面再加入一个跟s1登场的空间,每当s1循环移动之后,就把移到末尾的字符在前面空间中加一个,那么情况如下所示: ABCD----ABCDA----ABCDAB----ABCDABC--

【最小生成树杂题】

这里谈一下最小生成树 生成树的概念:连通图G的一个子图如果是一棵包含G的所有顶点的树,则该子图称为G的生成树.生成树是连通图的极小连通子图.所谓极小是指:若在树中任意增加一条边,则将出现一个回路:若去掉一条边,将会使之变成非连通图. 生成树各边的权值总和称为生成树的权.权最小的生成树称为最小生成树. 最小生成树一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边.常用于求最小生成树得算法包括kruskal(克鲁斯卡尔)算法或Prim(

POJ C程序设计进阶 编程题#2:字符串中次数第2多的字母

编程题#2:字符串中次数第2多的字母 来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 65536kB 描述 输入一串长度不超过500个符号的字符串,输出在串中出现第2多的英语字母(大小写字母认为相同)和次数(如果串中有其它符号,则忽略不考虑).如果有多个字母的次数都是第2多,则按串中字母出现的顺序输出第1个. 例 ab&dcAab&c9defgb 这里,a 和 b都出现3次,c和d都出现2

_杂题_

杂题集 是个放题的好地方! **** 5.28 **** - BZOJ [3052] 糖果公园 - 据说是一道区间操作的综合题,但现在貌似蹦了? 现在还是太水,之后再来写吧. *************

[杂题]URAL1822. Hugo II&#39;s War

看懂题意的请直接跳过下一坨! 本人有表达障碍! ========================================== 题意: (题意真的很难很难懂啊!!!  去他娘的**) 有一个王国,王国里有一个国王(编号为1),他有(编号为2~n) n-1个臣子(这些臣子并不全和他有直接关系) 然后呢 国王要去打架,但是只有当他的x%个及以上的直系下属(与他有直接关系的臣子)做好打架的准备了,他才能去打架 他的直系下属也有下属,也要其中x%及以上的下属做好打架准备了,那些直系下属才会开始准备

hdu 4961 数学杂题

http://acm.hdu.edu.cn/showproblem.php?pid=4961 先贴个O(nsqrtn)求1-n所有数的所有约数的代码: vector<int>divs[MAXN]; void caldivs() { for(int i=1;i<MAXN;i++) for(int j=i;j<MAXN;j+=i) divs[j].push_back(i); } 有了这个当时理下思路就可写了,但是重复数处理注意: 1.用一个数组vis[]  vis[i]=1表示i存在

poj 杂题 - 1959 Darts

这一题放在杂题里,是因为我没有用DP,而是使用的枚举,当然是受到了discuss里面的启发. 因为我们只能有三次机会,每一次只可以是固定的63个数,所以枚举感觉更加直观,但是不知道是不是没有DP快. #include<stdio.h> #include<string.h> int n; int Darts[63]; int main(){ int t,c=1,i,j,k,res; scanf("%d",&t); for(i = 0 ;i<=20;i

poj 杂题 - 2081 Recaman&#39;s Sequence

这道题目一开始就能知道考点在如何缩短查找时间.所以加快查找是我们的重点.但是在大数据面前,查找算法都不够快,所以我们用简单的hash思想来做. 我们开一个数组a,当出现了一个数b时,把该数作为下标调整值,即a[b] = -1,下一次出现该值的时候直接去找这个值作为下标的a值是否为-1即可. #include<stdio.h> #include<string.h> #define MAX 5000010 int p[MAX]={0}; int s[MAX]={0}; int main