算法练习-字符翻转
练习问题来源
https://wizardforcel.gitbooks.io/the-art-of-programming-by-july/content/01.01.html
要求:
给 定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串的尾部,使得原 字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。
解法:三步反转法
#include <stdio.h>
#include <stdlib.h>
// 把字符一个一个地移动到字符串的尾部
/*void LeftShiftOne(char* s, int n)
{
char t = s[0];
for (int i = 1; i < n; i++)
{
s[i-1] = s[i];
}
s[n-1] = t;
}
void LeftRotateString(char* s, int n, int m)
{
while(m--)
{
LeftShiftOne(s, n);
}
}*/
// 例如,字符串 abcdef ,若要让def翻转到abc的前头,只要按照下述3个步骤操作即可:
// 1. 首先将原字符串分为两个部分,即X:abc,Y:def;
// 2. 将X反转,X->X^T,即得:abc->cba;将Y反转,Y->Y^T,即得:def->fed。
// 3. 反转上述步骤得到的结果字符串X^TY^T,即反转字符串cbafed的两部分(cba和fed)给予反转,
// cbafed得到defabc,形式化表示为(X^TY^T)^T=YX,这就实现了整个反转。
void ReverseString(char* s, int from, int to)
{
char t;
while(from < to)
{
t = s[from];
s[from++] = s[to];
s[to--] = t;
}
}
void LeftRotateString(char* s, int n, int m) // 字符串长度 n, 翻转前 m 个
{
m %= n; //若要左移动大于n位,那么和%n 是等价的
ReverseString(s, 0, m-1);
ReverseString(s, m, n-1);
ReverseString(s, 0, n-1);
}
void main()
{
char s[7] = {'s', 't', 'u', 'i', '4', '5', 'm'};
for (int i=0; i<7; i++)
{
printf("%c ", s[i]);
}
printf("\n");
LeftRotateString(s, 7, 4);
for (int i=0; i<7; i++)
{
printf("%c ", s[i]);
}
}
相关练习
链表翻转。给出一个链表和一个数k,比如,链表为1→2→3→4→5→6,k=2,则翻转后2→1→6→5→4→3,若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→6→5。
/* List.h */ #ifndef _List_H #define _List_H struct Node; typedef struct Node *PtrToNode; typedef PtrToNode List; typedef PtrToNode Position; typedef int ElementType; List MakeEmpty(List L); int IsEmpty(List L); int IsLast(Position P, List L); Position Find(ElementType X, List L); void Delete(ElementType X, List L); Position FindPrevious(ElementType X, List L); void Insert(ElementType X, List L, Position P); void DeletList(List L); struct Node { ElementType Element; Position Next; }; #endif
/* List.cpp */ #include "List.h" #include <stdlib.h> #include <stdio.h> // Return true if L is empty, 测试链表是否为空表 int IsEmpty(List L) { return L->Next == NULL; } // Return true if P is the last position in list L // Parameter L is unused in this implementation // 测试当前位置是否是链表末尾 int IsLast(Position P, List L) { return P->Next == NULL; } // Return Position of X in L; NULL if not found Position Find(ElementType X, List L) { Position P; P = L->Next; while(P != NULL && P->Element != X) P = P->Next; return P; } void Delete(ElementType X, List L) { Position P, TmpCell; P = FindPrevious(X, L); if (!IsLast(P, L)) { TmpCell = P->Next; P->Next = TmpCell->Next; //P->Next->Next; free(TmpCell); } } Position FindPrevious(ElementType X, List L) { Position P; P = L; while(P->Next != NULL && P->Next->Element != X) P = P->Next; return P; } // Insert (after legal position) // Header implementation assumed // Parameter L is unused in this implementation void Insert(ElementType X, List L, Position P) { Position TmpCell; TmpCell = (struct Node*)malloc(sizeof(struct Node)); if (TmpCell == NULL) printf("Fatal Error: Out of space!!"); TmpCell->Element = X; TmpCell->Next = P->Next; P->Next = TmpCell; } void DeleteList(List L) { Position P, Tmp; P = L->Next; L->Next = NULL; // Header assumed while(P != NULL) { Tmp = P->Next; free(P); P = Tmp; } }
#include <stdio.h> #include <stdlib.h> #include "List.h" // 链表翻转: // 给出一个链表和一个数k,比如,链表为1→2→3→4→5→6,k=2,则翻转后2→1→6→5→4→3, // 若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→6→5 void ListReverseFunc(List L, int k, int m) { while (k < m) { int ikPos = 1; int imPos = 1; Position pkPos, pmPos; pkPos = L->Next; pmPos = L->Next; while(ikPos < k) { pkPos = pkPos->Next; ikPos++; } while(imPos < m) { pmPos = pmPos->Next; imPos++; } // 交换 k, m 位置的值 pkPos->Element = pkPos->Element + pmPos->Element; pmPos->Element = pkPos->Element - pmPos->Element; pkPos->Element = pkPos->Element - pmPos->Element; k++; m--; } } void main() { // 定义一个链表 ListReverse typedef PtrToNode List; List ListReverse; ListReverse = (struct Node*)malloc(sizeof(struct Node)); // 对链表赋值 1, 2,..., 7 Position P = ListReverse; for (int i = 1; i < 8; ++i) { P->Next = (struct Node*)malloc(sizeof(struct Node)); Insert(i, ListReverse, P); P = P->Next; } P->Next = NULL; // 赋值结束, 链表尾部, 置空 // k = 3, 反转链表 int k = 5; ListReverseFunc(ListReverse, 1, k); ListReverseFunc(ListReverse, k+1, 7); // 输出翻转结果 P = ListReverse->Next; while(!IsLast(P, ListReverse)) { printf("%d, ", P->Element); P = P->Next; } printf("%d\n", P->Element);
DeleteList(ListReverse); }