實現字串左旋和右旋的常見方法
說起字串的左旋和右旋問題,想必大家都不陌生,這是一個在初學C語言過程中經常遇到的一個問題,解題的思路可以說很多,每一個人的看待問題的角度都不同,所以就可以得到不同的解題思路。下面我就列舉幾種方法:
先從最容易想到的說起:
以字串abcdef為例,若是左旋問題,首先我們可以拿出首個字元a,將其與後面的每一個字元交換一次,得到新的字串bcdefa,然後進行交換得到cdefab,迴圈執行,一直到次數等於你給定的次數。(右旋與此類似)
程式碼如下所示:
void LRevolve_Words(char *Pword, int k, int len) //左旋,k為指定的左旋字元的個數 { int i = len; char temp; while (k--) { for ( i = 0; i < len - 1 ; i++) //依次交換 { temp = *(Pword + i); *(Pword + i) = *(Pword + i + 1); *(Pword + i + 1) = temp; } } }
void RRevolve_Words(char *Pword, int k, int len) //右旋
{
int i = len;
char temp;
while (k--)
{
for ( i = len ; i > 1 ; i--)
{
temp = *(Pword + i - 1);
*(Pword + i - 1) = *(Pword + i - 2);
*(Pword + i - 2) = temp;
}
}
}
上面的方法是最簡單的,也容易想到,實現起來簡單,程式碼容易理解,但是最主要的缺點就是效率不高,如果不考慮時間和空間的限制,假設移動的位為k,則要迴圈k次,每次迴圈移動1位,這樣的空間複雜度是0(1),時間複雜度是0(n*k),如果k大於n,則0(n^2)。因此,如果K>N,右移K - N之後的陣列序列跟右移K位的結果是一樣的。
下面介紹一種比較巧妙地方法:(個人認為也是最好的方法)
採用先部分再整體的方法(或者先整體再部分,效果差不多):具體實現是先反轉前k個字元,然後再反轉後n - k個字元,最後再反轉整個字串。這種方法比上面一種方法高效。時間複雜度是0(n),空間複雜度為0(1)。
這種方法也叫三步反轉法。(以左旋為例,右旋與之類似)
#include<stdio.h> #include <string.h> #include<assert.h> #define Max_Words 20 void Reverse_String(char * Pword, char * qword) { char *pa = Pword; char *pb = qword; char temp; assert(Pword); assert(qword); while (pa<pb) { temp = *pa; *pa = *pb; *pb = temp; pa++; pb--; } } int main() { char arr[Max_Words]; int len = 0; int k = 0; char *pStart = NULL; char *pEnd = NULL; printf("請輸入您要旋轉的字串內容\n"); scanf("%s", arr); len = strlen(arr) - 1; printf("請輸入您要旋轉的字元個數\n"); scanf("%d", &k); pStart = &arr[0]; pEnd = arr + len; Reverse_String(pStart, pStart + k - 1); //把要左旋的k個字元先逆序翻轉 Reverse_String(pStart + k, pEnd); //把k+1後的字元逆序翻轉 Reverse_String(pStart, pEnd); //整個字串逆序翻轉 printf("旋轉之後的字串為:%s\n", arr); return 0; }
接著再介紹一種不是一下子可以想到的方法。就是用遞迴,當然不是說這方法很難,只是我們不經常用這方法,或者說如果不提醒你,你是無法一下子想到的。(一般會提示你請用遞迴方法解決)
當然遞迴也有不同的遞迴方式:
方式一:
每次向右移動K位,最後遞迴,把一個規模為N的問題化解為規模為M(M<N)的問題。
舉例來說,設字串總長度為L,左側要旋轉的部分長度為s1,那麼當從左向右迴圈交換長度為s1的小段,直到最後,由於剩餘的部分長度為s2(s2==L%s1)而不能直接交換。
該問題可以遞迴轉化成規模為s1+s2的,方向相反(從右向左)的同一個問題。隨著遞迴的進行,左右反覆迴盪,直到某一次滿足條件L%s1==0而交換結束。可以說是第一種方法更好地展示。
方式二:
先說左旋,每次都把一個元素拿出來,然後將把一個元素先拿出來,放在一個臨時變數temp之中,並把這個元素改成‘\0’,然後進行遞迴,直到達到指定的次數,遞迴結束,之後進行遞迴的返回,返回後依次拿出之前儲存的temp賦值給最後面元素之後的一個空間,(當然這裡需要額外的空間,定義的陣列要比字串內容大)。
void LRevolve_Words(char *Pword , int k , int len) //len為陣列內容的大小
{
char temp;
assert(Pword);
if (k)
{
temp = *Pword;
*Pword = '\0'; //將首字元改成‘\0’
LRevolve_Words(Pword + 1, k - 1 , len);
*(Pword + len ) = temp;
}
*(Pword + len + k) = '\0';
}
再說右旋,與左旋稍有不同,在遞迴的過程中首先要將每一個字元向後面移動一位,然後取出最後面的一個元素,並放入temp之中,然後再改成'\0',然後進行遞迴,遞迴返回的時候,將前面元素賦值成後面要旋轉的元素。void RRevolve_Words(char *Pword , int k , int len)
{
char temp;
int i;
assert(Pword);
if (k)
{
temp = Pword[len - 1];
for ( i = 0; i < len ; i++)
{
Pword[len - i ] = Pword[len - i - 1];
}
Pword[len] = '\0';
RRevolve_Words(Pword + 1, k - 1 , len - 1);
*Pword = temp;
}
}
其實還有許多其他的方法,總之沒有最好只有更好,大家也可以多多去探索!
相關推薦
實現字串左旋和右旋的常見方法
說起字串的左旋和右旋問題,想必大家都不陌生,這是一個在初學C語言過程中經常遇到的一個問題,解題的思路可以說很多,每一個人的看待問題的角度都不同,所以就可以得到不同的解題思路。下面我就列舉幾種
java實現迴圈左移和右移的簡單演算法
byte a=112,用程式實現,將其迴圈左移三位和右移三位。 112的二進位制原碼:0111 0000 112迴圈左移3位後的二進位制碼:1000 0011 112迴圈右移3位後的二進位制碼:0000 1110 先將迴圈左移的程式程式碼告訴大家: public clas
C語言實現字串迴圈左移和右移
C語言實現迴圈左移和右移這個沒有什麼好說的,直接上程式碼:#include <stdio.h> //寫一個函式 實現功能:輸入字串,向右迴圈或者逆時針移動N位元組,再輸出這個字串 /* //比如:左移2位元組 //左邊不變,右邊變 p[0
C語言三種方法實現字串左旋
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<assert.h> void
紅黑樹的左旋和又旋
今天先來用java實現紅黑色左旋和右旋。後邊再把新增、刪除給補充上。 什麼是紅黑樹? 紅黑樹是一種近似平衡的二叉查詢樹,它能夠確保任何一個節點的左右子樹的高度差不會超過二者中較低那個的一陪。具體來說,紅黑樹是滿足如下條件的二叉查詢樹(binary search tree): 每個節
【演算法】紅黑樹插入資料(變色,左旋、右旋)(二)
本人菜雞一隻,正在更新紅黑樹系列的文章。 該系列到現在暫只有3篇文章: 【演算法】紅黑樹(二叉樹)概念與查詢(一):https://blog.csdn.net/lsr40/article/details/85230703 【演算法】紅黑樹插入資料(變色,左旋、右旋)(二
樹的左旋與右旋
下圖所示操作稱為對結點Q的右旋,對結點P的左旋。二者互為逆操作。 簡單講,右旋——自己變為左孩子的右孩子;左旋——自己變為右孩子的左孩子。 #include class BinTree{ private: typedef struct node{ int da
建立紅黑樹(左旋、右旋、插入、維護)程式碼+驗證
關於紅黑樹的理論講解,網上有很多,大家可以自己找,這裡重點在於實現,程式碼供大家參考。程式碼如下: #include <stdio.h> #include <stdlib.h> #include <time.h> #includ
給定一個字串實現對字串左移或右移指定長度
給定一個字串S[0,1,...,N-1],要求把S的前k個字元移動到S的尾部,如把字串"abcdef"前面的2個字元'a','b'移動到字串的尾部,得到新字串“cdefab”;即字串迴圈左移k #i
(C語言)BinarySrearchTree二叉搜尋樹 --- 標準插入(遞迴,非遞迴)、遍歷(前,中,後序)、查詢(遞迴,非遞迴)、根插入遞迴(左旋,右旋)、最小最大值、刪除節點
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 struct node{ 5 int data; 6 struct node *left; 7
【Python】最長括號匹配問題:給定字串,僅包含左括號‘(’和右括號‘)’,它可能不是括號匹配的,設計演算法,找出最長匹配的括號子串
最長括號匹配 示例: 給定字串,僅包含左括號‘(’和右括號‘)’,它可能不是括號匹配的,設計演算法,找出最長匹配的括號子串。 演算法分析 只有在右括號和左括號發生匹配時,才有可能更新最終解。 計算s[0…i]中左括號數目與右括號數目的差
佈局:高度已知,佈局一個三欄佈局,左欄和右欄寬度為200px,中間自適應 浮動佈局詳解
需求:高度已知為200px,寫出三欄佈局,左欄和右欄各位200px,中間自適應,如下圖所示: 方法一:float浮動佈局 原理是:定義三個區塊,需要注意的是中間的區塊放在右邊區塊的下面,統一設定高度為200px,然後設定左邊欄寬度為200px並且float:left,設定右邊欄寬度為200px並且fl
C++ 判斷左值和右值 (使用程式碼判斷)
C++的左值和右值的概率繼承自C語言裡。C++11之後引入右值。 左值和右值的根本區別就是左值可以使用&取地址,而右值是不可以取地址的。還有一點就是,右值是可以賦值給左值,但是反過來就不行,即左值不能賦值給右值。通俗的講,就是左值在=左邊,右值在右邊。 其實我們如果在判斷左值和右
java (邏輯與&&、按位與&、邏輯或||、按位或|、異或^、左移和右移)的區別?
首先名稱是不同的 &&邏輯與 ||邏輯或 它們都是邏輯運算子 & 按位與 | 按位或 它們都是位運算子 if(a==1&&b==2) 這是說既要滿足a=1也要滿足b=2 if(a==
C++中讓人忽視的左值和右值
前言 為了瞭解C++11的新特性右值引用,不得不重新認識一下左右值。學習之初,最快的理解,莫過於望文生義了,右值那就是賦值號右邊的值,左值就是賦值號左邊的值。在中學的數學的學習中,我們理解的是,左值等價於等號左邊的值,右值等價於等號右邊的值;當我們繼續學習C語言時,等號=不再叫等號,蓋頭換面叫做
C++進階--理解左值和右值
/* * 理解左值和右值 * * * 為什麼要關心這個? * 1. 有助於理解C++結構,搞明白編譯器的錯誤和警告 * 2. C++ 11中引入了右值引用,理解左值右值是前提 * */ /* * 簡單的定義: * * 左值 - 在記憶體中具有可標識位置的物件 * 右值 - 任何不是
表的內連線和外連結(左連線和右連線)
表的內連線 內連線是利用where子句對兩種表形成的笛卡爾積進行篩選。 select 欄位 from 表1 inner join 表2 on 連線條件 and 其他條件; inner可以省略 and可以換成where 例:顯示SMITH的名字和部門名稱 emp表: dept表:
C語言位運算子:與、或、異或、取反、左移和右移
語言位運算子:與、或、異或、取反、左移和右移 位運算是指按二進位制進行的運算。在系統軟體中,常常需要處理二進位制位的問題。C語言提供了6個位操作運算子。這些運算子只能用於整型運算元,即只能用於帶符號或無符號的char,short,int與long型別。 C語言提供的位運算
C/C++裡面的左移和右移
int i = 1;i = i << 2; //把i裡的值左移2位也就是說,1的2進位制是000...0001(這裡1前面0的個數和int的位數有關,32位機器,gcc裡有31個0),左移2位之後變成000... 0100,也就是10進位制的4,所以說左移1位相當於乘以2,那麼左移n位就是乘以2的
用遞迴的思想寫編寫一個函式reverse_string(char * string)實現字串反向輸出和反向排列
字串反向輸出: #include<stdio.h> void reverse_string(char *string) { if ('\0'!=*(++string))