1. 程式人生 > >劍指Offer題解(三)字串問題

劍指Offer題解(三)字串問題

#include<vector>
using namespace std;

//	getline(cin, str); //一行一行輸入可輸入空格

#pragma region 替換空格 字串

//請實現一個函式,將一個字串中的每個空格替換成“%20”。
//例如,當字串為We Are Happy.則經過替換之後的字串為We%20Are%20Happy。

#pragma endregion

class Solution {
public:
	void replaceSpace(char *str, int length) {
		int len = 0;
		for (int i = 0; i < length; i++)
		{
			if (str[i] != ' ')
				len++;
			else
			{
				len += 3;
			}
		}
		char *pStr1 = str + len;
		char *pStr2 = str + length;
		while (pStr2 != pStr1)
		{
			if (*pStr2 == ' ')
			{
				*pStr1-- = '0';
				*pStr1-- = '2';
				*pStr1-- = '%';
			}
			else
			{
				*pStr1-- = *pStr2;
			}
			pStr2--;
		}
	}
};


#pragma region 第一個只出現一次的字元
//在一個字串(0<=字串長度<=10000,全部由字母組成)中找到第一個只出現一次的字元,並返回它的位置, 如果沒有則返回 -1(需要區分大小寫).

#pragma endregion

class Solution {
public:
	int FirstNotRepeatingChar(string str) {
		int hashTable[255];
		for (int i = 0; i < 256; i++)
		{
			hashTable[i] = 0;
		}
		for (int i = 0; i < str.length(); i++)
		{
			hashTable[str[i]] ++;
		}
		for (int i = 0; i < str.length(); i++)
		{
			if (hashTable[str[i]] == 1)
				return i;
		}
		return -1;
	}
};

#pragma region 字串的排列 字串 遞迴 全排列

//輸入一個字串, 按字典序打印出該字串中字元的所有排列。例如輸入字串abc, 則打印出由字元a, b, c所能排列出來的所有字串abc, acb, bac, bca, cab和cba。
#pragma endregion

class Solution {
public:
	vector<string> retStrings;
	void PermutationChar(string str, int i)
	{
		if (i == str.size() - 1)
			retStrings.push_back(str);
		else
		{
			for (int j = i; j < str.size(); j++)
			{
				if (i != j && str[i] == str[j])
					continue;
				else
				{
					swap(str[i], str[j]);
					PermutationChar(str, i + 1);
				}
			}
		}
	}
	vector<string> Permutation(string str) {
		PermutationChar(str, 0);
		return retStrings;
	}
};


#pragma region 正則表示式匹配 字串 遞迴
//請實現一個函式用來匹配包括'.'和'*'的正則表示式。模式中的字元'.'表示任意一個字元,而'*'表示它前面的字元可以出現任意次(包含0次)。
//在本題中,匹配是指字串的所有字元匹配整個模式。例如,字串"aaa"與模式"a.a"和"ab*ac*a"匹配,但是與"aa.a"和"ab*a"均不匹配

#pragma endregion

class Solution {
public:
	bool match(char* str, char* pattern)
	{
		if (str == nullptr || pattern == nullptr)
			return false;
		return matchCore(str, pattern);
	}
	bool matchCore(char* str, char* pattern)
	{
		if (*str == '\0' && *pattern == '\0')
			return true;

		if (*str != '\0' && *pattern == '\0')
			return false;

		if (*(pattern + 1) == '*')
		{
			if (*pattern == *str || (*pattern == '.' && *str != '\0'))
				return matchCore(str + 1, pattern + 2) || matchCore(str + 1, pattern) || matchCore(str, pattern + 2);
			else
				return matchCore(str, pattern + 2);
		}

		if (*str == *pattern || (*pattern == '.' && *str != '\0'))
			return matchCore(str + 1, pattern + 1);

		return false;
	}
};


#pragma region 表示數值的字串 字串 數字 數值
//請實現一個函式用來判斷字串是否表示數值(包括整數和小數)。例如,字串"+100","5e2","-123","3.1416"和"-1E-16"都表示數值。
//但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

#pragma endregion

class Solution {
public:
	bool isNumeric(char* string)
	{
		if (string == nullptr)
			return false;

		bool numeric = isInteger(&string);

		if (*string == '.')
		{
			++string;

			numeric = isUnsignedInteger(&string) || numeric;
		}

		if (*string == 'e' || *string == 'E')
		{
			++string;

			numeric = numeric && isInteger(&string);
		}

		return numeric && *string == '\0';
	}
	bool isUnsignedInteger(char** str)
	{
		const char* tem = *str;
		bool ret = false;
		while (**str != '\0' && **str >= '0' && **str <= '9')
		{
			++(*str);
			ret = true;
		}
		return ret;
	}
	bool isInteger(char** str)
	{
		if (**str == '+' || **str == '-')
			++(*str);
		return isUnsignedInteger(str);
	}

};



//牛客中不要用itoa 	改用		sprintf(char*, "%d", int);

#pragma region 把字串轉換成整數  atoi 
//將一個字串轉換成一個整數(實現Integer.valueOf(string)的功能,但是string不符合數字要求時返回0),要求不能使用字串轉換整數的庫函式。 
//數值為0或者字串不是一個合法的數值則返回0。
#pragma endregion

class Solution {
public:
	int StrToInt(string str) {
		if (str.length() < 1)
			return 0;
		long long num = 0;
		bool isNegtive = false;
		bool isValid = true;
		int ret = 0;
		char* charStr = strdup(str.c_str());
		if (*charStr == '-')
		{
			isNegtive = true;
			++charStr;
		}
		else if (*charStr == '+')
		{
			++charStr;
		}
		while (*charStr != '\0')
		{
			if (*charStr < '0' || *charStr > '9')
			{
				isValid = false;
				return 0;
			}
			else
			{
				ret = ret * 10 + *charStr - '0';
			}
			++charStr;
		}
		if (isNegtive)
		{
			ret = -ret;
			if (ret < INT_MIN)
			{
				isValid = false;
				return 0;
			}
		}
		else
		{
			if (ret > INT_MAX)
			{
				isValid = false;
				return 0;
			}
		}
		int retInt = (int)ret;
		return retInt;
	}
};



#pragma region 字元流中第一個不重複的字元  字串 流 雜湊

//請實現一個函式用來找出字元流中第一個只出現一次的字元。例如,當從字元流中只讀出前兩個字元"go"時,第一個只出現一次的字元是"g"。
//當從該字元流中讀出前六個字元“google"時,第一個只出現一次的字元是"l"。

//如果當前字元流沒有存在出現一次的字元,返回#字元。
#pragma endregion

class Solution
{

public:
	int occurence[256] = { 0 };
	string str;
	//Insert one char from stringstream
	void Insert(char ch)
	{
		str += ch;
		++occurence[ch];
	}

	//return the first appearence once char in current stringstream
	char FirstAppearingOnce()
	{
		char ret = '#';
		for (int i = 0; i < str.size(); ++i)
		{
			if (occurence[str[i]] == 1)
			{
				ret = str[i];
				break;
			}
		}
		return ret;
	}
};


#pragma region 左旋轉字串  字串 翻轉 反轉 

//組合語言中有一種移位指令叫做迴圈左移(ROL),現在有個簡單的任務,就是用字串模擬這個指令的運算結果。
//對於一個給定的字元序列S,請你把其迴圈左移K位後的序列輸出。
//例如,字元序列S=”abcXYZdef”,要求輸出迴圈左移3位後的結果,即“XYZdefabc”。是不是很簡單?OK,搞定它!
#pragma endregion

class Solution {
public:
	void ReverseString(char *str, const int &begin, const int &end)
	{
		char  *charStart = str + begin;
		char  *charEnd = str + end;
		while (charStart < charEnd)
		{
			char tem = *charStart;
			*charStart = *charEnd;
			*charEnd = tem;
			++charStart;
			--charEnd;
		}
	}
	string LeftRotateString(string str, int n) {
		if (n < 0 || n > str.length() - 1)
			return str;
		//string.h
		//char * charStr = new char[strlen(str.c_str()) + 1];
		//strcpy(charStr, str.c_str());
		char* charStr = strdup(str.c_str());
		ReverseString(charStr, 0, n - 1);
		ReverseString(charStr, n, str.length() - 1);
		ReverseString(charStr, 0, str.length() - 1);
		string ret;
		ret = charStr;
		return ret;
	}
};


#pragma region 翻轉單詞順序列   字串 翻轉 反轉 
//牛客最近來了一個新員工Fish,每天早晨總是會拿著一本英文雜誌,寫些句子在本子上。
//同事Cat對Fish寫的內容頗感興趣,有一天他向Fish借來翻看,但卻讀不懂它的意思。
//例如,“student. a am I”。後來才意識到,這傢伙原來把句子單詞的順序翻轉了,正確的句子應該是“I am a student.”。
//Cat對一一的翻轉這些單詞順序可不在行,你能幫助他麼?
#pragma endregion


class Solution {
public:
	void ReverseString(char *str, const int &begin, const int &end)
	{
		char  *charStart = str + begin;
		char  *charEnd = str + end;
		while (charStart < charEnd)
		{
			char tem = *charStart;
			*charStart = *charEnd;
			*charEnd = tem;
			++charStart;
			--charEnd;
		}
	}
	string ReverseSentence(string str) {
		int begin = 0;
		int end = 1;
		char* charStr = strdup(str.c_str());
		while (end <= str.length())
		{
			if (charStr[end] == ' ' || charStr[end] == '\0')
			{
				ReverseString(charStr, begin, end - 1);
				begin = end + 1;
			}
			++end;
		}
		ReverseString(charStr, 0, str.length() - 1);
		string ret;
		ret = charStr;
		return ret;
	}
};




#pragma region 把陣列排成最小的數 字串 陣列 排序 qsort sort
//輸入一個正整數陣列,把數組裡所有數字拼接起來排成一個數,列印能拼接出的所有數字中最小的一個。
//例如輸入陣列{3,32,321},則打印出這三個數字能排成的最小數字為321323。
#pragma endregion

class Solution {
public:
	static int compare(const void* strNumber1, const void* strNumber2)
	{
		char* g_StrCombine1 = new char[10 * 2 + 1];
		char* g_StrCombine2 = new char[10 * 2 + 1];
		strcpy(g_StrCombine1, *(const char**)strNumber1);
		strcat(g_StrCombine1, *(const char**)strNumber2);

		strcpy(g_StrCombine2, *(const char**)strNumber2);
		strcat(g_StrCombine2, *(const char**)strNumber1);

		return strcmp(g_StrCombine1, g_StrCombine2);
	}
	string PrintMinNumber(vector<int> numbers) {
		string ret;
		if (numbers.size() < 1)
			return ret;
		char** strNumbers = (char**)malloc(sizeof(char*)* numbers.size());
		for (int i = 0; i < numbers.size(); ++i)
		{
			strNumbers[i] = new char[10 + 1];
			sprintf(strNumbers[i], "%d", numbers[i]);
		}
		qsort(strNumbers, numbers.size(), sizeof(char*), compare);

		for (int i = 0; i < numbers.size(); ++i)
			ret += strNumbers[i];

		free(strNumbers);
		return ret;
	}

};




#pragma region 全排列 九宮格 電話號碼 轉 字元組合 

#pragma endregion

class Solution {
public:

	string str[8] = { "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };
	vector<string> retVector;
	vector<string> letterCombinations(string digits) {
		int len = digits.length();
		if (len <= 0)
			return retVector;
		for (int i = 0; i < len; ++i)
		{
			if (digits[i] < '2' || digits[i] > '9')
			{
				return retVector;
			}
		}
		string a;
		letterCombinationsRecursive(digits, 0, len, a);
		return retVector;
	}
	void letterCombinationsRecursive(string &digits, int begin, const int &length, string beforeStr) {
		if (begin == length)
		{
			retVector.push_back(beforeStr);
		}

		for (int i = 0; i < str[digits[begin] - '2'].length(); ++i)
		{
			letterCombinationsRecursive(digits, begin + 1, length, beforeStr + str[digits[begin] - '2'][i]);
		}

	}
};
int main(int argc, char* argv[])
{
	Solution sl;
	vector<string> retVector = sl.letterCombinations("23456");
}