笔试算法和数据结构--字符串移动算法

算法和数据结构是笔试和技术面必会涉及的内容,而且与编程有关最为基础也是最为重要的也是这一块,而目前笔记的题目往往是从公司的题库中抽取的,"猜中"的可能性还是比较大的,但如何去猜,并不是说我们上网把那什么面试宝典上的题全记一遍,但如果记性好,那也可以,比如那什么排序,查找考的可能性较大的,但是这样对于自己的思维上的提高真的帮助很小,这些天看算法和数据结构下来,发现很多的算法的思想方法是相通的,如果再了解如何去权衡时间复杂度和空间复杂度,如何优化自己的算法,这个过程才是最为重要的.

总结这些的学习,什么是符合题意的算法,网上基本都找的到,我觉得如果要记录下,最主要的是记录思考过程及思想方法.

PS.有些算法直接摘自网络,方便阅读.

什么左旋字体串,其它定义为把字符串前面若干个字符移动到字符串的尾部

设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),
且只允许使用两个附加变量。

如:

abcd1234→4abcd123→34abcd12→234abcd1→1234abcd。

这里的字符串的移动主要是通过字符交换完成.

这里我们可以发现其右移后的字符串和未移时的相比,可以明显的分段,即abcd和1234,两子段的顺序没有变化.

这里我们给出一个思路,因为循环右移的整体感觉就是两个子段的交换位置

法一,常用的方法是:先将子段逆顺,然后再整体逆序.

我们可以这样理解,反反得正.即我们最终换的只是子段的位置,而不改变子段的顺序,而我们先将子段逆序,再整体逆序最终结果是子段内顺序的还原,

用数学表示

1、首先分为俩部分,X:abc,Y:def;
2、X->X^T,abc->cba, Y->Y^T,def->fed。
3、(X^TY^T)^T=YX,cbafed->defabc,即整个翻转。
附上代码:
a.
#include<stdio.h>
#include<string.h>
#define offset 3
void reverse(char *array,int b,int e);
int main()
{
    int i=0;
    char array[11]="abcde12345";
    int len=strlen(array);
    reverse(array,0,offset);  //左移位数
    reverse(array,offset+1,len-1); 
    reverse(array,0,len-1);
    for(i=0;i<len;i++){
        printf("%c",array[i]);
        }
    printf("\n");
       return 0; 
        }
void reverse(char *array,int b,int e){
        for(;b<e;b++,e--){
            array[b]^=array[e];
            array[e]^=array[b];   //这是不用辅助变量的交换方法,主要的原理是x^y^y=x;y^x^x=y;
            array[b]^=array[e];
            }
        }
输出结果:e12345abcd
法二,通过双指针来实现:如果是左移一位,我们如何实现,就是将第一个元素移至最后一位,那在这里我们就可以将要移动的个数打个包,整体来看,同样是将第一个包移至最后一位,只不过这个包移一位,涉及多位的移动.
比如上例中的abcde12345678
1,abcd--e1234  -->e1234abcd  #include<stdio.h>
2如果所以元素划分包是整份的,则重复第1步换abcd-5678得最终结果e12345678abcd
3如果数为abcde123456789,起始换第一步,得到最后结果为e12345678abcd98,则进行第四步
4,将最后的分别将9和8移到abcd前,得最终的结果e1234567898abcd
代码b:
#include<string.h>
#define M 4
void reverse(char *array,int length,int m);
void swap(char *a,char *b);
int main(){
    char array[]="abcdefghijkljk";
    int len=strlen(array);
    reverse(array,len,M);
    int i;
    for(i=0;i<len;i++){
        printf("%c",array[i]);
        }
    printf("\n");
    return 0;
    }
void swap(char *a,char *b){ 
        *a^=*b;
        *b^=*a;
        *a^=*b;
        }
void reverse(char *array,int length,int m){
        int p1=0,p2=m;
        int k=(length/m-1)*m;
        while(k--){
            swap(array+p1,array+p2);
             p1++;
             p2++;
            }
        int r=length%m; //乘下的字符个数
        while(r--){
            int i=p2;
            while(i>p1){
                swap(array+i,array+i-1);
                i--;
                }
            p1++;
           p2++;
            }
        }
运行结果:efghijkljkabcd
总结:
这里主要用到的是整体和个体的关系,即个体的划分不是固定的,而是相对的.有些时候可以将几个元素看成一个整体处理.
数组的移动靠的是交换,如果首尾交换成形逆序,相临元素的交换则是顺序移动,但如果两次首尾交换,一个子段,一次整段,刚可以实现块的移动.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值