数据结构:字符串 C++

本文介绍了C++实现的字符串操作,包括旋转字符串、判断字符串包含、字符串转换成整数、回文判断、最长回文字串以及字符串全排列的问题,每个问题都附有详细的分析和C++代码实现。
摘要由CSDN通过智能技术生成

题目来自于

https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/01.00.md

非常感谢July大神和众网友。


本博文初衷是为了方便自己准备面试,有一篇文章可以看所有的东西,省的翻来翻去。

代码是手打的Qt C++,解法中不考虑实现最简单的毫无难度的暴力解法了。

因为很短,不区分*.cc和*.hh文件了,都写在一起; 注释初衷也是为了自己理解。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

1.1 旋转字符串

题目描述

给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串的尾部,使得原字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。

分析与C++实现

// 编程之美:1.1旋转字符串

// 题目:给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,
// 如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串的尾部,使得原
// 字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字
// 符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。
#include <iostream>
#include <string>
using namespace std;
// 记得用reference,不然改变后的string传不回来
void leftShiftString(string& str, int shiftNum);
void reverseString(string& str, int from, int to);
void rotate(string& str, int shiftNum);
int main()
{
  
    string test_str = "abcd";
    int shiftNumber = 2;
    cout << "before: " << test_str << endl;
    //leftShiftString(test_str, shiftNumber);
    rotate(test_str, shiftNumber);
    cout << "after : " << test_str << endl;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// 推荐解法: 三步翻转法
// 将一个字符串分成X和Y两个部分,在每部分字符串上定义反转操作,如X^T,即把X的所有字符反转
// (如,X="abc",那么X^T="cba"),那么就得到下面的结论:(X^TY^T)^T=YX,显然就解决了字符串的反转问题。
// 例如,字符串 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 leftShiftString(string& str, int shiftNum)
{
  
    int str_len = str.length();
    if (str_len == 0)
    {
  
        // 空串忽视
        return;
    }else
    {
  
        // 取模两个好处:一是避免不必要的移动,
        // 二是防止index越界,尤其是shiftNum可能有负值,这时候要加上str_len避免取模返回负值
        shiftNum = (shiftNum + str_len) % str_len;
    }
    if (shiftNum == 0)
    {
  
        //移动0位可以直接返回
        return;
    }
    // 原字符串的X部分 -> X^T
    reverseString(str, 0, shiftNum - 1);
    cout << "X part: " << str << endl;
    // 原字符串的Y部分 -> Y^T
    reverseString(str, shiftNum, str_len - 1);
    cout << "Y part: " << str << endl;
    // (X^TY^T)^T -> YX
    reverseString(str, 0, str_len - 1);
    cout << "Both part: " << str << endl;
}
void reverseString(string& str, int from, int to)
{
  
    while(from < to)
    {
  
        swap(str[from++], str[to--]);
    }
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//其他解法: 不是很通用,但是我自己想出来的,见
//http://blog.csdn.net/u013300875/article/details/44126909
//思路简单说就是我们知道str_len,也知道shiftNum,所以对于一个特定位置current的字符,
//它的目标位置target其实就确定了,我们只要把这它从current移动到target就行了
void rotate(string& str, int shiftNum)
{
  
    int str_len = str.length();
    if (str_len == 0)
    {
  
        // 空串忽视
        return;
    }
    if (shiftNum == 0)
    {
  
        //移动0位可以直接返回
        return;
    }
    //每个字符应该只被移动一次,也必须也被移动一次
    //所以我们在 count == str_len 时停止
    int count = 0;
    for (int i = 0; i < str_len ; ++i)
    {
  
        int index = i;
        char tmp = str[index];
        while(1)
        {
  
            count++;
            // 在index位置的字符将被移动到index+new
            int index_new = (index - shiftNum + str_len) % str_len;
            // 把index_new位置的元素保存到空出来的i位置
            str[i] = str[index_new];
            // 完成str[index] -> str[index_new]的移动
            str[index_new] = tmp;
            // 准备处理原来位于index_new的字符
            tmp = str[i];
            index = index_new;
            // 如果我们已经处理了所有的字符,即完成了一个圈
            // 我们是从i这个位置开始处理的,如果我们下一个要处理的又是i,
            // 我们可以跳过它了
            if (i == index)
            {
  
                break;
            }
        }
        if (count == str_len)
        {
  
            break;
        }
    }
}


1.2 字符串包含

题目描述

给定两个分别由字母组成的字符串A和字符串B,字符串B的长度比字符串A短。请问,如何最快地判断字符串B中所有字母是否都在字符串A里?

为了简单起见,我们规定输入的字符串只包含大写英文字母,请实现函数bool StringContains(string &A, string &B)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值