第二章、字符串各种小问题

本文深入探讨了字符串处理的基本算法及其在实际场景中的应用,包括字符串包含问题、匹配问题、查找子串、唯一字符查找、整数转换、字符串拷贝等核心功能,通过实例分析了每种算法的时间复杂度和优化策略。

问题一:一长一短字符串的包含问题
问题描述:假设这有一个各种字母组成的字符串,假设这还有另外一个字符串,而且这个字符串里的字母数相对少一些。从算法是讲,什么方法能最快的查出所有小字符串里的字母在大字符串里都有?
比如,如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPOM
答案是true,所有在string2里的字母string1也都有。

如果是下面两个字符串:  
String 1: ABCDEFGHLMNOPQRS   
String 2: DCGSRQPOZ  
答案是false,因为第二个字符串里的Z字母不在第一个字符串里。

思路一:O(n*m)的轮询方法
 判断一个字符串是否在另一个字符串中,最直观也是最简单的思路是,针对第二个字符串string2中每一个字符,一一与第一个字符串string1中每个字符依次轮询比较,看它是否在第一个字符串string1中。假设n是字符串string1的长度,m是字符串string2的长度,那么此算法,需要O(n*m)次操作.

#include <iostream>
using namespace std;

int CompareSting(string LongSting,string ShortSting)
{
	for (int i=0; i<ShortString.length(); i++)
	{
		for (int j=0; j<LongString.length(); j++)  //O(n*m)
		{
			if (LongString[i] == ShortString[j])  //一一比较
			{
				break;
			}
			
		}
		if (j==LongString.length())
		{
			cout << "false" << endl;
			return 0;
		}
	}
	cout << "true" << endl;
	return 1;
}

int main() 
{ 
	string LongString="ABCDEFGHLMNOPQRS";
	string ShortString="DCGSRQPOM";
	compare(LongString,ShortString);
	return 0;
}


思路二:O(mlogm)+O(nlogn)+O(m+n)的排序方法
此方案是先对这两个字符串的字母进行排序,然后同时对两个字串依次轮询。两个字串的排序需要(常规情况)O(m log m) + O(n log n)次操作,之后的线性扫描需要O(m+n)次操作。对于排序大家都知道一般都是采用快速排序。排序的代码就不写了。然后可以看看查找的代码。

#include <iostream>
#include <string>
using namespace std;

//比较,上述排序O(m log m) + O(n log n),加上下面的O(m+n),
//时间复杂度总计为:O(mlogm)+O(nlogn)+O(m+n)。
void compare(string str1,string str2)
{
	int posOne = 0;
	int posTwo = 0;
	while (posTwo < str2.length() && posOne < str1.length())
	{
		while (str1[posOne] < str2[posTwo] && posOne < str1.length() - 1)
			posOne++;
		//如果和str2相等,那就不能动。只有比str2小,才能动。
		
		if (str1[posOne] != str2[posTwo])
			break;
		
		//posOne++;   
		//归并的时候,str1[str1Pos] == str[str2Pos]的时候,只能str2Pos++,str1Pos不可以自增。
		//多谢helloword指正。

		posTwo++;
	}
				
	if (posTwo == str2.length())
		cout << "true" << endl;
	else
		cout << "false" << endl;
}

int main() 
{ 
	string str1 = "ABCDEFGHLMNOPQRS";
	string str2 = "DCGDSRQPOM";  
	

	quicksort(str1, 0, str1.length() - 1);
	quicksort(str2, 0, str2.length() - 1);  //先排序
	compare(str1, str2);                    //后线性扫描
	return 0;
}


思路三:O(m+n)的计数排序方法
此方案与上述思路相比,就是在排序的时候采用线性时间的计数排序方法,排序O(n+m),线性扫描O(n+m),总计时间复杂度为:O(n+m)+O(n+m)=O(n+m)。

#include <iostream>
#include <string>
using namespace std;

// 计数排序,O(n+m)
void CounterSort(string str, string &help_str)
{
	// 辅助计数数组
	int help[26] = {0};

	// help[index]存放了等于index + 'A'的元素个数
	for (int i = 0; i < str.length(); i++)
	{
		int index = str[i] - 'A';
		help[index]++;
	}

	// 求出每个元素对应的最终位置
    for (int j = 1; j < 26; j++)
		help[j] += help[j-1];

	// 把每个元素放到其对应的最终位置
	for (int k = str.length() - 1; k >= 0; k--)
	{
		int index = str[k] - 'A';
		int pos = help[index] - 1;
		help_str[pos] = str[k];
		help[index]--;
	}
}

//线性扫描O(n+m)
void Compare(string long_str,string short_str)
{
	int pos_long = 0;
	int pos_short = 0;
	while (pos_short < short_str.length() && pos_long < long_str.length())
	{
		// 如果pos_long递增直到long_str[pos_long] >= short_str[pos_short]
		while (long_str[pos_long] < short_str[pos_short] && pos_long < long_str.length() - 1)
			pos_long++;
		
		// 如果short_str有连续重复的字符,pos_short递增
		while (short_str[pos_short] == short_str[pos_short+1])
			pos_short++;

		if (long_str[pos_long] != short_str[pos_short])
			break;
		
		pos_long++;
		pos_short++;
	}
	
	if (pos_short == short_str.length())
		cout << "true" << endl;
	else
		cout << "false" << endl;
}

int main()
{
	string strOne = "ABCDAK";
	string strTwo = "A";
	string long_str = strOne;
	string short_str = strTwo;

	// 对字符串进行计数排序
	CounterSort(strOne, long_str);
	CounterSort(strTwo, short_str);

	// 比较排序好的字符串
	Compare(long_str, short_str);
	return 0;
}
思路四:O(m+n)的hashtable的方法
我们可以对短字串进行轮询,把其中的每个字母都放入一个Hashtable里(我们始终设m为短字符串的长度,那么此项操作成本是O(m))。然后轮询长字符串,在Hashtable里查询短字符串的每个字符,看能否找到。如果找不到,说明没有匹配成功,轮询长字符串将消耗掉n次操作,这样两项操作加起来一共只有(m+n)次。当然,理想情况是如果长字串的前缀就为短字串,只需消耗m次操作,这样总共只需2m次。
算法如下:1、hash[26],先全部清零,然后扫描短的字符串,若有相应的置1,
       2、计算hash[26]中1的个数,记为m 
       3、扫描长字符串的每个字符a;若原来hash[a] == 1 ,则修改hash[a] = 0,并将m减1;若hash[a] == 0,则不做处理 
     4、若m == 0 or 扫描结束,退出循环。
#include <iostream>
#include <string>
using namespace std;

int main()
{
	string str1="ABCDEFGHLMNOPQRS";
	string str2="DCGSRQPOM";

	// 开辟一个辅助数组并清零
	int hash[26] = {0};

	// num为辅助数组中元素个数
	int num = 0;

	// 扫描短字符串
	for (int j = 0; j < str2.length(); j++)
	{
		// 将字符转换成对应辅助数组中的索引
		int index = str1[j] - 'A';

		// 如果辅助数组中该索引对应元素为0,则置1,且num++;
		if (hash[index] == 0)
		{
			hash[index] = 1;
			num++;
		}
	}

	// 扫描长字符串
	for (int k = 0; k < str1.length(); k++)
	{
		int index = str1[k] - 'A';

		// 如果辅助数组中该索引对应元素为1,则num--;为零的话,不作处理(不写语句)。
		if(hash[index] ==1)
		{
			hash[index] = 0;
			num--;
			if(num == 0)    //m==0,即退出循环。
				break;
		}
	}

	// num为0说明长字符串包含短字符串内所有字符
	if (num == 0)
		cout << "true" << endl;
	else
		cout << "false" << endl;
	return 0;
}
思路四:O(m+n)的数组存储的方法(此思路与思路三本质上一样的)
有两个字符串short_str和long_str。
 1:你标记short_str中有哪些字符,在store数组中标记为true。(store数组起一个映射的作用,如果有A,则将第1个单元标记true,如果有B,则将第2个单元标记true,... 如果有Z, 则将第26个单元标记true)
  2:遍历long_str,如果long_str中的字符包括short_str中的字符则将store数组中对应位置标记为false。(如果有A,则将第1个单元标记false,如果有B,则将第2个单元标记false,... 如果有Z, 则将第26个单元标记false),如果没有,则不作处理。
3:此后,遍历store数组,如果所有的元素都是false,也就说明store_str中字符都包含在long_str内,输出true。否则,输出false。
#include<iostream>
#include<string.h>
using namespace std;

int main()
{
	char long_ch[]="ABCDEFGHLMNOPQRS";
	char short_ch[]="DEFGHXLMNOPQ";
	int i;
	bool store[58];
	memset(store,false,58);  
	
	//前两个 是  遍历 两个字符串, 后面一个是  遍历 数组
	for(i=0;i<sizeof(short_ch)-1;i++)
		store[short_ch[i]-65]=true;
	
	for(i=0;i<sizeof(long_ch)-1;i++)
	{
		if(store[long_ch[i]-65]!=false)
			store[long_ch[i]-65]=false;
	}
	for(i=0;i<58;i++)
	{
		if(store[i]!=false)
		{
			cout<<"short_ch is not in long_ch"<<endl;
			break;  
		}        
		if(i==57)
			cout<<"short_ch is in long_ch"<<endl;
	}
	
	return 0;
}

思路五:O(n)到O(m+n)的素数的方法
假设我们有一个一定个数的字母组成字串,我给每个字母分配一个素数,从2开始,往后类推。这样A将是2,B将会是3,将会是5,等等。现在我遍历第一个字串,把每个字母代表的素数相乘。 然后轮询第二个字符串,用每个字母除它。如果除的结果有余数,这说明有不匹配的字母。如果整个过程中没有余数,你应该知道它是第一个字串恰好的子集了。
思路总结如下:
1.定义最小的26个素数分别与字符'A'到'Z'对应。
2.遍历长字符串,求得每个字符对应素数的乘积。
3.遍历短字符串,判断乘积能否被短字符串中的字符对应的素数整除。
4.输出结果。
#include <iostream>
#include <string>
#include "BigInt.h"
using namespace std;

// 素数数组
int primeNumber[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
						61, 67, 71, 73, 79, 83, 89, 97, 101};

int main()
{
	string strOne = "ABCDEFGHLMNOPQRS";
	string strTwo = "DCGSRQPOM";

	// 这里需要用到大整数
	CBigInt product = 1;   //大整数除法的代码,下头给出。

	// 遍历长字符串,得到每个字符对应素数的乘积
	for (int i = 0; i < strOne.length(); i++)
	{
		int index = strOne[i] - 'A';
		product = product * primeNumber[index];
	}

	// 遍历短字符串
	for (int j = 0; j < strTwo.length(); j++)
	{
		int index = strTwo[j] - 'A';

		// 如果余数不为0,说明不包括短字串中的字符,跳出循环
		if (product % primeNumber[index] != 0)
			break;
	}

	// 如果积能整除短字符串中所有字符则输出"true",否则输出"false"。
	if (strTwo.length() == j)
		cout << "true" << endl;
	else
		cout << "false" << endl;
	return 0;
}
以下的大整数除法的代码:
//实现大整数类
#include <string>
#include <vector>
#include <iostream>
using namespace std;

class CBigInt
{
public:
	// input
	friend istream& operator >> (istream &, CBigInt &);
	// output
	friend ostream& operator << (ostream &os, const CBigInt &value)
	{
		if (value.bigInt[0] == '-')
			os << value.bigInt;
		else
		{
			// 正数不输出符号
			os << value.bigInt.substr(1);
		}
		return os;
	}
	friend bool operator == (const CBigInt &, const CBigInt &);
	friend bool operator < (const CBigInt &lValue, const CBigInt &rValue)
	{
		if (lValue.bigInt[0] != rValue.bigInt[0])
		{
			// '+'ASCII码为43,'-'ASCII码为45
			return lValue.bigInt[0] > rValue.bigInt[0];
		}
		else
		{
			if (lValue.bigInt[0] == '+')
				return lValue.smaller(rValue.bigInt);		// 正数的情况
			else
				return lValue.greater(rValue.bigInt);		// 负数的情况
		}
	}
	
	friend bool operator > (const CBigInt &lValue, const CBigInt &rValue)
	{
		if (lValue.bigInt[0] != rValue.bigInt[0])
			return lValue.bigInt[0] < rValue.bigInt[0];
		else
		{
			if (lValue.bigInt[0] == '+')
				return lValue.greater(rValue.bigInt);
			else
				return lValue.smaller(rValue.bigInt);
		}
	}
	string bigInt;
public:
	CBigInt();
	CBigInt(int);
	CBigInt(const string &);
	CBigInt(const CBigInt &);
	CBigInt(const char *);
	CBigInt& operator = (const CBigInt &);
	CBigInt& operator += (const CBigInt &);
	CBigInt& operator -= (const CBigInt &);
	CBigInt& operator *= (const CBigInt &);
	CBigInt& operator /= (const CBigInt &);
	CBigInt& operator %= (const CBigInt &);
	
	// prefix increment
	CBigInt& operator ++ ();
	// prefix decrement
	CBigInt& operator -- ();
	// postfix increment
	CBigInt operator ++ (int);
	// postfix decrement
	CBigInt operator -- (int);
private:
	// unsigned +=
	void plus(const string &);
	// unsigned -=
	void minus(const string &);
	// unsigned ==
	bool equal(const string &) const;
	// unsigned <
	bool smaller(const string &) const;
	// unsigned >
	bool greater(const string &) const;
};

/************************************************************************/
/* 构造函数                                                              
/************************************************************************/
// 默认构造函数
inline CBigInt::CBigInt() : bigInt("+0")
{}

// 构造函数
inline CBigInt::CBigInt(const string &str) : bigInt(str)
{
	if (bigInt.size() > 0)
	{
		// 没有正负符号
		if (bigInt[0] != '+' && bigInt[0] != '-')
		{
			string::size_type i = 0;
			for (; i < bigInt.size() - 1 && bigInt[i] == '0'; i++);
			if (i > 0)
				bigInt.replace((string::size_type)0, i, "+");
			else
				bigInt.insert((string::size_type)0, 1, '+');
		} 
		else
		{
			if (bigInt.size() == 1)
				bigInt = "+0";
			else
			{
				string::size_type j = 1;
				// 去掉多余的0
				for (; j < bigInt.size() - 1 && bigInt[j] == '0'; j++);
				if (j > 1)
					bigInt.erase((string::size_type)1, j - 1);
				if (bigInt == "-0")
					bigInt = "+0";
			}
		}
	} 
	else
		bigInt = "+0";
}

// 复制构造函数
inline CBigInt::CBigInt(const CBigInt &value) : bigInt(value.bigInt)
{}

inline CBigInt::CBigInt(int num)
{
	if (num == 0)
		bigInt = "+0";
	else if (num > 0)
		bigInt = '+';
	else
	{
		bigInt = '-';
		num *= -1;
	}
	string temp = "";
	while (num != 0)
	{
		temp += num % 10 + '0';
		num = num / 10;
	}
	for (int i = temp.size() - 1; i >= 0; i--)
		bigInt += temp[i];
}

inline CBigInt::CBigInt(const char *str) : bigInt(str)
{
	if (bigInt.size() > 0)
	{
		if (bigInt[0] != '+' && bigInt[0] != '-')
		{
			string::size_type i = 0;
			// 去除多余的0
			for (; i < bigInt.size() - 1 && bigInt[i] == '0'; i++);
			if (i > 0)
				bigInt.replace((string::size_type)0, i, "+");
			else
				bigInt.insert((string::size_type)0, 1, '+');
		} 
		else
		{
			if (bigInt.size() == 0)
				bigInt = "+0";
			else
			{
				string::size_type j = 1;
				for (; j < bigInt.size() - 1 && bigInt[j] == '0'; j++);
				if (j > 1)
					bigInt.erase((string::size_type)1, j - 1);
				// 处理特殊情况“-0”
				if (bigInt == "-0")
					bigInt = "+0";
			}
		}
	} 
	else
		bigInt = "+0";
}

inline bool operator == (const CBigInt &lValue, const CBigInt &rValue)
{
	return lValue.bigInt == rValue.bigInt;
}

inline bool operator != (const CBigInt &lValue, const CBigInt &rValue)
{
	return !(lValue.bigInt == rValue.bigInt);
}

inline bool operator <= (const CBigInt &lValue, const CBigInt &rValue)
{
	return !(lValue > rValue);
}

inline bool operator >= (const CBigInt &lValue, const CBigInt &rValue)
{
	return !(lValue < rValue);
}

inline CBigInt& CBigInt::operator = (const CBigInt &value)
{
	bigInt = value.bigInt;
	return *this;
}

// unsigned ==
inline bool CBigInt::equal(const string &value) const
{
	return bigInt.substr(1) == value.substr(1);
}

// unsigned <
inline bool CBigInt::smaller(const string &value) const
{
	if (bigInt.size() == value.size())
		return bigInt.substr(1) < value.substr(1);
	else
		return bigInt.size() < value.size();
}

// unsigned >
inline bool CBigInt::greater(const string &value) const
{
	if (bigInt.size() == value.size())
		return bigInt.substr(1) > value.substr(1);
	else
		return bigInt.size() > value.size();
}

/************************************************************************/
/* 实现+,-,*,/运算                                                                     
/************************************************************************/
void CBigInt::plus(const string &value)
{
	if (bigInt.size() < value.size())
		bigInt.insert((string::size_type)1, (value.size() - bigInt.size()), '0');
	string::size_type i = bigInt.size() - 1;
	string::size_type j = value.size() - 1;
	while (j > 1)
	{
		bigInt[i] += value[j] - '0';
		if (bigInt[i] > '9')
		{
			bigInt[i] -= 10;
			++bigInt[i-1];
		}
		i--;
		j--;
	}
	
	// 最高位进位
	bigInt[i] += value[1] - '0';
	while (i > 1 && bigInt[i] > '9')
	{
		bigInt[i] -= 10;
		i--;
		++bigInt[i];
	}
	
	if (bigInt[1] > '9')
	{
		bigInt[1] -= 10;
		bigInt.insert((string::size_type)1, 1, '1');
	}
}

void CBigInt::minus(const string &vlaue)
{
	string::size_type i = bigInt.size() - 1;
	string::size_type j = vlaue.size() - 1;
	while (j >= 1)
	{
		bigInt[i] -= vlaue[j] - '0';
		if (bigInt[i] < '0')
		{
			bigInt[i] += 10;
			--bigInt[i-1];
		}
		i--;
		j--;
	}
	
	// 向前借位
	while (i > 1 && bigInt[i] < '0')
	{
		bigInt[i] += 10;
		i--;
		--bigInt[i];
	}
	
	// 去除多余的0
	string::size_type k = 1;
	for (; k < bigInt.size() - 1 && bigInt[k] == '0'; k++);
	if (k > 1)
		bigInt.erase((string::size_type)1, k - 1);
}

CBigInt& CBigInt::operator += (const CBigInt &value)
{
	if (bigInt[0] == value.bigInt[0])
		plus(value.bigInt);
	else
	{
		// 互为相反数的情况
		if (equal(value.bigInt))
			bigInt = "+0";
		// 绝对值小于的情况
		else if (smaller(value.bigInt))
		{
			string temp = bigInt;
			bigInt = value.bigInt;
			minus(temp);
		}
		else
			minus(value.bigInt);
	}
	return *this;
}

CBigInt& CBigInt::operator -= (const CBigInt &value)
{
	// 处理过程与+=类似
	if (bigInt[0] == value.bigInt[0])
	{
		if (equal(value.bigInt))
			bigInt = "+0";
		else if (smaller(value.bigInt))
		{
			string temp = bigInt;
			bigInt = value.bigInt;
			minus(temp);
			if (bigInt[0] == '+')
				bigInt[0] = '-';
			else
				bigInt[0] = '+';
		}
		else
			minus(value.bigInt);
	}
	else
		plus(value.bigInt);
	return *this;
}

CBigInt operator + (const CBigInt &lValue, const CBigInt &rValue)
{
	CBigInt sum(lValue);
	sum += rValue;
	return sum;
}

CBigInt operator - (const CBigInt &lValue, const CBigInt &rValue)
{
	CBigInt diff(lValue);
	diff -= rValue;
	return diff;
}

// prefix increment
CBigInt& CBigInt::operator ++ ()
{
	string::size_type i = bigInt.size() - 1;
	if (bigInt[0] == '+')
	{
		++bigInt[i];
		while (i > 1 && bigInt[i] > '9')
		{
			bigInt[i] -= 10;
			i--;
			++bigInt[i];
		}
		
		if (bigInt[i] > '9')
		{
			bigInt[i] -= 10;
			bigInt.insert((string::size_type)1, 1, '1');
		}
	} 
	else
	{
		--bigInt[i];
		while(i > 1 && bigInt[i] < '0')
		{
			bigInt[i] += 10;
			i--;
			--bigInt[i];
		}
		
		string::size_type j = 1;
		for (; j < bigInt.size() - 1 && bigInt[j] == '0'; j++);
		if (j > 1)
			bigInt.erase(1, j - 1);
		
		if (bigInt[1] == '0')
			bigInt[0] = '+';
	}
	return *this;
}

CBigInt& CBigInt::operator -- ()
{
	string::size_type i = bigInt.size() - 1;
	// 对正数和负数分别处理
	if (bigInt[0] == '+')
	{
		// 对0进行处理
		if (bigInt[1] == '0')
			bigInt = "-1";
		else
		{
			--bigInt[i];
			while (i > 1 && bigInt[i] < '0')
			{
				bigInt[i] += 10;
				i--;
				--bigInt[i];
			}
			
			string::size_type j = 1;
			for (; j < bigInt.size() - 1 && bigInt[j] == '0'; j++);
			if (j > 1)
				bigInt.erase(1, j - 1);
		}
	}
	else
	{
		++bigInt[i];
		while (i > 1 && bigInt[i] > '9')
		{
			bigInt[i] -= 10;
			i--;
			++bigInt[i];
		}
		
		if (bigInt[1] > '9')
		{
			bigInt[1] += 10;
			bigInt.insert((string::size_type)1, 1, '1');
		}
	}
	return *this;
}

// postfix increment
CBigInt CBigInt::operator ++ (int)
{
	CBigInt temp(*this);
	++(*this);
	return temp;
}

// postfix decrement
CBigInt CBigInt::operator -- (int)
{
	CBigInt temp(*this);
	--(*this);
	return temp;
}

// 模拟笔算过程
CBigInt& CBigInt::operator *= (const CBigInt &value)
{
	// 乘数或被乘数有一方为0则返回结果0
	if (bigInt[1] == '0' || value.bigInt[1] == '0')
	{
		bigInt = "+0";
		return *this;
	}
	
	string::size_type sizeofMultiplicand = bigInt.size();
	string::size_type sizeofMultiplier = value.bigInt.size();
	vector<unsigned int> product(sizeofMultiplier + sizeofMultiplicand - 1);
	
	// 初始化
	for (string::size_type i = 1; i < sizeofMultiplicand; ++i)
		bigInt[i] -= '0';
	
	
	// 笔算乘法过程
	for (string::size_type j = sizeofMultiplier - 1; j > 0; --j)
	{
		if (value.bigInt[j] > '0')
		{
			for (string::size_type k = sizeofMultiplicand - 1; k > 0; --k)
				product[k+j] += bigInt[k] * (value.bigInt[j] - '0');
		}
	}
	
	// 处理符号
	if (bigInt[0] == value.bigInt[0])
		product[0] = '+';
	else
		product[0] = '-';
	
	vector<unsigned int>::size_type sizeofProduct = product.size();
	bigInt = string(sizeofProduct, '0');
	bigInt[0] = product[0];
	
	// 处理进位问题
	for (vector<unsigned int>::size_type n = sizeofProduct - 1; n > 1; --n)
	{
		product[n-1] += product[n] / 10;
		product[n] %= 10;
		bigInt[n] += product[n];
	}
	
	if (product[1] == 0)
		bigInt.erase(1, 1);
	else
		bigInt[1] += product[1];
	
	return *this;		
}

// 重复做差法求商
CBigInt& CBigInt::operator /= (const CBigInt &value)
{
	// 除数为0
	if (value.bigInt == "+0")
	{
		bigInt = "*Error!";
		return *this;
	}
	
	// 被除数大于除数
	if (value.smaller(bigInt) == true)
	{
		string::size_type sizeofDividend = bigInt.size();
		string::size_type sizeofDivisor = value.bigInt.size();
		string answer(sizeofDividend, '0');
		
		// 符号处理
		if (bigInt[0] == value.bigInt[0])
			answer[0] = '+';
		else
			answer[0] = '-';
		
		string::size_type start = 1;
		string::size_type end = sizeofDivisor - 1;
		
		while (end < sizeofDividend)
		{
			// 试商过程,从高位到低位
			while (value.greater(bigInt.substr(start - 1, end - start + 2)) == 

false)
			{
				string::size_type j = end;
				// 减法过程
				for (string::size_type i = sizeofDivisor - 1; i > 0; i--, j--)
				{
					bigInt[j] -= value.bigInt[i] - '0';
					if (bigInt[j] < '0')
					{
						bigInt[j] += 10;
						--bigInt[j-1];
					}
				}
				
				// 商的相应位加1
				++answer[end];
				
				// 以除数做边界去掉前缀0
				while (start <= end && bigInt[start] == '0')
					++start;
			}
			
			// 以被除数做边界去掉前缀0
			while (start < sizeofDividend && bigInt[start] == '0')
				++start;
			
			// 如果end-start+1 < sizeofDivisor - 1,则进行补位
			if (end - start + 2 < sizeofDivisor)
				end = sizeofDivisor + start - 2;
			else
				++end;
		}
		start = 1;
		for (; start < answer.size() - 1 && answer[start] == '0'; ++start);
		if (start > 1)
			answer.erase(1, start - 1);

		bigInt = answer;
	} 
	// 绝对值相等的情况
	else if (value.equal(bigInt) == true)
	{
		string answer = "-1";
		if (bigInt[0] == value.bigInt[0])
			answer = "+1";
		bigInt = answer;
	}
	else
		bigInt = "+0";

	return *this;
}

// 求余,与上面去商过程基本一致
CBigInt& CBigInt::operator %= (const CBigInt &value)
{
	if (value.bigInt == "+0")
	{
		bigInt = "*Error!";
		return *this;
	}

	// 求余,余数为剩余bigInt值
	if (value.smaller(bigInt) == true)
	{
		string::size_type sizeofDivident = bigInt.size();
		string::size_type sizeofDivisor = value.bigInt.size();

		string::size_type start = 1;
		string::size_type end = sizeofDivisor - 1;
		while (end < sizeofDivident)
		{
			// 除数的值不大于被除数的值
			while (value.greater(bigInt.substr(start - 1, end - start + 2)) == 

false)
			{
				string::size_type j = end;
				for (string::size_type i = sizeofDivisor - 1; i > 0; --i, --j)
				{
					bigInt[j] -= value.bigInt[i] - '0';
					if (bigInt[j] < '0')
					{
						bigInt[j] += 10;
						--bigInt[j-1];
					}
				}

				while (start <= end && bigInt[start] == '0')
					++start;
			}

			while (start < sizeofDivident && bigInt[start] == '0')
				++start;

			if (end - start + 2 < sizeofDivisor)
				end = sizeofDivisor + start - 2;
			else
				++end;
		}

		start = 1;
		for (; start < sizeofDivident - 1 && bigInt[start] == '0'; start++);

		if (start > 1)
			bigInt.erase(1, start - 1);

		if (bigInt == "-0")
			bigInt[0] = '+';
	}
	else if (value.equal(bigInt))
		bigInt = "+0";
	return *this;
}

CBigInt operator * (const CBigInt &lValue, const CBigInt &rValue)
{
	CBigInt product(lValue);
	product *= rValue;
	return product;
}

CBigInt operator / (const CBigInt &lValue, const CBigInt &rValue)
{
	CBigInt quotient(lValue);
	quotient /= rValue;
	return quotient;
}

CBigInt operator % (const CBigInt &lValue, const CBigInt &rValue)
{
	CBigInt mod(lValue);
	mod %= rValue;
	return mod;
}

问题二:字符串匹配问题
问题描述:假设两个字符串中所含有的字符和个数都相同我们就叫这两个字符串匹配,比如:abcda和adabc,由于出现的字符个数都是相同,只是顺序不同,所以这两个字符串是匹配的。分析:可以看出,此字符串的匹配问题,是与上述字符串包含的问题相类似的,这个问题可以先排序再比较,也可以利用hash表进行判断。这里给出一种hash表的方法,原理已在上文中阐明了,代码如下:

#include <iostream>
#include <string>
using namespace std;

bool Is_Match(const char *strOne,const char *strTwo)
{
	int lenOfOne = strlen(strOne);
	int lenOfTwo = strlen(strTwo);

	// 如果长度不相等则返回false
	if (lenOfOne != lenOfTwo)
		return false;

	// 开辟一个辅助数组并清零
	int hash[26] = {0};
	
	// 扫描字符串
	for (int i = 0; i < strlen(strOne); i++)
	{
		// 将字符转换成对应辅助数组中的索引
		int index = strOne[i] - 'A';
		
		// 辅助数组中该索引对应元素加1,表示该字符的个数
		hash[index]++;
	}

	// 扫描字符串
	for (int j = 0; j < strlen(strTwo); j++)
	{
		int index = strTwo[j] - 'A';
		
		// 如果辅助数组中该索引对应元素不为0则减1,否则返回false
		if (hash[index] != 0)
			hash[index]--;
		else
			return false;
	}
	return true;
}

int main()
{
	string strOne = "ABBA";
	string strTwo = "BBAA";
	
	bool flag = Is_Match(strOne.c_str(), strTwo.c_str());
	
	// 如果为true则匹配,否则不匹配
	if (flag == true)
		cout << "Match" << endl;
	else
		cout << "No Match" << endl;
	return 0;
}

问题三:在字符串中查找子串
问题描述:给定一个字符串A,要求在A中查找一个子串B。如A="ABCDF",要你在A中查找子串B=“CD”。分析:比较简单,相当于实现strstr库函数,主体代码如下:

int strstr(char *string,char *substring) 
{
	int len1=strlen(string);
	int len2=strlen(substring);
	for (int i=0; i<=len1-len2; i++)   //复杂度为O(m*n)
	{
		for (int j=0; j<len2; j++)
		{
			if (string[i+j]!=substring[j])
				break;
		}
		if (j==len2)
			return i+1;
	}
	return 0;
} 

问题四:在一个字符串中找到第一个只出现一次的字符分析:先遍历一遍字符数组,把字符放到对应位置的数字数组中,然后再开始遍历字符数组,查找数字数组。

#include <iostream>
using namespace std;

char find_first_unique_char(char *str)
{
	int data[256];
	char *p;
	
	if (str == NULL)
		return '/0';
	
	memset(data, 0, sizeof(data));    //数组元素先全部初始化为0
	p = str;
	while (*p != '/0')
		data[(unsigned char)*p++]++;  //遍历字符串,在相应位置++,(同时,下标强制转换)
	
	while (*str != '/0')
	{
		if (data[(unsigned char)*str] == 1)  //最后,输出那个第一个只出现次数为1的字符
			return *str;
		
		str++;
	}
	
	return '/0';
}

int main()
{
	char *str = "afaccde";
	cout << find_first_unique_char(str) << endl;
	return 0;
}

问题五:字符串转换为整数
题目:输入一个表示整数的字符串,把该字符串转换成整数并输出。例如输入字符串"345",则输出整数345。分析:此题看起来,比较简单,每扫描到一个字符,我们把在之前得到的数字乘以10再加上当前字符表示的数字。这个思路用循环不难实现。然其背后却隐藏着不少陷阱,正如zhedahht 所说,有以下几点需要你注意:

    1、由于整数可能不仅仅之含有数字,还有可能以'+'或者'-'开头,表示整数的正负。如果第一个字符是'+'号,则不需要做任何操作;如果第一个字符是'-'号,则表明这个整数是个负数,在最后的时候我们要把得到的数值变成负数。
    2、如果使用的是指针的话,在使用指针之前,我们要做的第一件是判断这个指针是不是为空。如果试着去访问空指针,将不可避免地导致程序崩溃此第2点在下面的程序不需注意,因为没有用到指针
    3、输入的字符串中可能含有不是数字的字符。
每当碰到这些非法的字符,我们就没有必要再继续转换。
    4、溢出问题。由于输入的数字是以字符串的形式输入,因此有可能输入一个很大的数字转换之后会超过能够表示的最大的整数而溢出。

    总结以上四点,代码可以如下编写

#include <iostream>
#include <string>
#include <assert.h>
using namespace std;

int str_2_int(string str)
{
	assert(str.size() > 0);
	
	int pos = 0;
	int sym = 1;
	
	// 处理符号
	if (str[pos] == '+')
		pos++;
	else if (str[pos] == '-')
	{
		pos++;
		sym = -1;
	}
	
	int num = 0;
	// 逐位处理
	while (pos < str.length())
	{
		// 处理数字以外的字符
		assert(str[pos] >= '0');
		assert(str[pos] <= '9');
		
		num = num * 10 + (str[pos] - '0');
		
		// 处理溢出
		assert(num >= 0);
		
		pos++;
	}
	
	num *= sym;
	
	return num;
}

int main()
{
	string str = "-1024";
	int num = str_2_int(str);
	cout << num << endl;
	return 0;
}

问题六:字符串的拷贝题目描述:要求实现库函数strcpy。
分析:如果编写一个标准strcpy函数的总分值为10,下面给出几个不同得分的答案:

//2分
void strcpy( char *strDest, char *strSrc )
{
    while( (*strDest++ = * strSrc++) != '/0' );
} 

//4分
void strcpy( char *strDest, const char *strSrc ) 
{
    //将源字符串加const,表明其为输入参数,加2分
    while( (*strDest++ = * strSrc++) != '/0' );
} 

//7分
void strcpy(char *strDest, const char *strSrc) 
{
    //对源地址和目的地址加非0断言,加3分
    assert( (strDest != NULL) && (strSrc != NULL) );
    while( (*strDest++ = * strSrc++) != '/0' );
} 

//10分
//为了实现链式操作,将目的地址返回,加3分!
char * strcpy( char *strDest, const char *strSrc ) 
{
    assert( (strDest != NULL) && (strSrc != NULL) );
    char *address = strDest; 
    while( (*strDest++ = * strSrc++) != '/0' ); 
    return address;
} 


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值