字符串的循環移位


問題描述:

  將一個字符串a像左旋轉i個位置。例如,當n=8且i=3時(n爲字符串有效長度),向量abcdefgh旋轉爲defghabc。要求時間複雜度O(n),空間複雜度爲O(1)

問題求解:

      直接將前i個數組複製到一個臨時數組,將餘下的元素左移,再將臨時數組中的i個元素複製到末尾的方法可得正確解,但空間複雜度爲O(n)。每次移動一個到末尾,剩餘的前移也能得正確解,但時間複雜度爲O(n^2)。顯然,我們需要新的想法。

     解法一:

    移動a[0]到臨時變量t,然後移動a[i]到a[0],a[2i]到x[i],依次類推(將a中所有下標對n取模),直至返回到取x[0]中的元素,此時改爲從t取值然後終止過程。

  代碼如下:

  

複製代碼
#include <stdio.h>
#include <string.h>

//求最大公約數
int gcd(int i,int j)
{
    while(i != j )
    {
        if(i > j)
            i = i - j;
        else
            j = j - i;
    }
    return i;
}

void turnleft(char *a,int i,int n)
{
     int left = i % n;
  
     if(left == 0)
          return ;

     int gcdnum = gcd(left,n);
     int j,k,t,m;
    
     for(j=0;j<gcdnum;j++)
     {
        t = a[j];     
         m = j;
         k = m + left;
         while(1)
        {
            k = m + left;
            if(k >= n)
                k = k - n;
            if(k == j)
                break;
            a[m] = a[k];
            m = k;
        }
        
        a[m] = t;

     }

}

int main()
{
    char a[1024];
    int i;
    printf("請輸入字符串: ");
    //fgets(a,1024,stdin);//fgets會將結尾的回車換行符也記錄下
    scanf("%s",a);
    printf("請輸入左移位數:");
    scanf("%d",&i);
    int n = strlen(a);
    turnleft(a,i,n);
    printf("%s\n",a);

}
複製代碼

 

 解法二:

   解法一滿足了我們的要求,但看起來仍然沒那麼直觀,有沒有更清晰移動的方法呢? 答案就是有。

     首先將字符串a分爲兩段,要移動的前i位爲b,剩餘部分爲c,則字符串可表示爲bc,左移i位的結果其實就是cb,則算法的目的就是將bc轉換爲cb。首先將b逆序爲b',再將c逆序爲c',最後將(b'c')'整體逆序即得到cb。 

    代碼如下:

 

複製代碼
#include <stdio.h>
#include <string.h>

//將a中從start到end翻轉
void reverse(char *a,int start, int end)
{
    int i ,j,temp;
    for(i = start,j = end; i < j; i++,j--)
    {
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
    
}


//a爲原數據,i爲要左翼的位數,n爲總長度
void turnleft(char *a,int i,int n)
{
    int left = i % n;

    if(left == 0)
        return ;

    reverse(a,0,left-1);
    reverse(a,left,n-1);
    reverse(a,0,n-1);
    return ;

}

int main()
{
    char a[1024];
    int i;
    printf("請輸入字符串: ");
    //fgets(a,1024,stdin);//fgets會將結尾的回車換行符也記錄下
    scanf("%s",a);
    printf("請輸入左移位數:");
    scanf("%d",&i);
    int n = strlen(a);
    turnleft(a,i,n);
    printf("%s\n",a);
}
複製代碼

 

      以上兩種算法均可以在O(n),O(1)內完成字符串的循環移位。也許有看觀會問,這裏說的都是循環左移,那循環又移怎麼辦呢? 呵,事實上,循環左移和循環右移本質上是一模一樣的,循環右移i位其實就是循環左移n-i位而已。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章