C ++中字符串转换的就地算法
对于给定的字符串,将所有偶数定位的元素转移到字符串的末尾。在传送元素时,请保持所有偶数和奇数元素的相对顺序相同。
例如,如果给定的字符串是“a1b2c3d4e5f6g7h8i9j1k2l3m4”,则将其就地转换为“abcdefghijklm1234567891234”,并且时间复杂度为O(n)。
以下是步骤
切出大小为3^k+1的最高前缀子字符串。在此步骤中,我们定位最高非负整数k,以使3^k+1小于或等于n(字符串的长度)。)
从该子字符串的索引1、3、9…开始,实施循环领导者迭代算法(已在下面说明)。循环领导迭代算法将这个子字符串的所有项目转移到它们的正确位置,这意味着,所有字母都移到了该子字符串的左半部分,所有数字都移到了该子字符串的右半部分。
递归地执行步骤no,处理其余的子字符串。1,没有。2。
目前,我们只需要将处理后的子字符串连接在一起。从任意一端开始(例如,从左开始),选择两个子字符串并执行以下步骤-
正好与第一个子字符串的后半部分相反或相反。
与第二个子字符串的前半部分相反或相反。
将第一子字符串的后半部分和第二子字符串的前半部分恰好相对或颠倒在一起。
重复步骤号。4,直到并且除非所有子串都被连接。它与第一个子字符串与第二个子字符串连接在一起的k路合并相同。结果与第三合并,依此类推。
下面是基于上述算法给出的代码-
// C++ application of above approach #include <bits/stdc++.h> using namespace std; //交换字符的实用程序函数voidswap(char*a1,char*b1){ char t = *a1; *a1 = *b1; *b1 = t; } //实用函数 void reverse ( char* str1, int low1, int high1 ) { while ( low < high ) { swap(&str1[low1], &str1[high1] ); ++low1; --high1; } } //循环领导算法将所有偶数平移 //最后放置元素。 void cycleLeader ( char* str1, int shift1, int len1 ) { int j; char item1; for (int i = 1; i < len1; i *= 3 ) { j = i; item1 = str1[j + shift1]; do{ // odd index if ( j & 1 ) j = len1 / 2 + j / 2; //偶数索引或位置,否则j/=2; //将元素的备份保持在新的索引或位置 swap (&str1[j + shift1], &item1); } while ( j != i ); } } //转换字符串的主要功能。此功能 // mainly implements cycleLeader() to convert void moveNumberToSecondHalf( char* str1 ) { int k, lenFirst1; int lenRemaining1 = strlen( str1); int shift1 = 0; while ( lenRemaining1) { k = 0; //步骤1:找到最高的前缀 //子数组 while ( pow( 3, k ) + 1 <= lenRemaining1) k++; lenFirst1 = pow( 3, k - 1 ) + 1; lenRemaining1 -= lenFirst1; //第2步:实施周期首长算法 //对于最高的子数组cycleLeader(str1,shift1,lenFirst1); //步骤4.1:与第一个子数组的后半部分相反或相反(str1, shift1/2, shift1 - 1 ); //步骤4.2:正好相反或反转第二个子字符串的前半部分。反向(str1, shift1, shift1 + lenFirst1 / 2 - 1 ); //前半部分 second sub-string together reverse ( str1, shift1 / 2, shift1 + lenFirst1 / 2 - 1 ); //现在增加第一个子数组Shift1+=lenFirst1;的长度; } } // Driver program to verify or test above function int main() { char str1[] = "a1b2c3d4e5f6g7"; moveNumberToSecondHalf( str1 ); cout<<str1; return 0; }
输出结果
abcdefg1234567