1. 程式人生 > >一道面試題引發的思考

一道面試題引發的思考

1.昨天(10月10日)騰訊一面,一道簡單的面試題,本以為寫得還不錯,結果今天回來仔細思考並coding,發現此程式中漏洞多多。

2.題意:刪除一個字串中重複出現的字元,只留下第一次出現的字元。如:輸入abaacdba,輸出abcd。

3.思路:定義一個數組來存放每個字元出現的次數,如果發現字元已經出現,則刪除該字元。

4.程式碼:

(1)當時寫的版本:

char* DeleteFun(char* str)
{
	int times[WordNumber];
	for (int i = 0; i < WordNumber; i++)
	{
		times[i] = 0;
	}

	char* p = str;
	int index;
	while (*p != '\0')
	{
		index = *p - 'a';
		if (times[index] == 0)
		{
			times[index]++;
		}
		p++;
	}

	p = str;
	char* ret = str;
	
	while (*p != '\0')
	{
		index = *p - 'a';
		if (times[index] != 0)
		{
			times[index] = 0;
			*ret = *p;
			ret++;
		}
		p++;
	}
	ret++;
	*ret = '\0';

	return str;
}
(2)當時檢查了一遍,發現沒有加 *ret = '\0'這一句,加上之後自以為還比較滿意。

5.回來發現的問題

(1)最後ret++是多餘的,有錯的,加了這一句會多一個字元;

(2)時間花費了2*N,開銷有點大;

(3)這裡只考慮了26個小寫字母,而沒有考慮大寫字母和特殊字元。

6.剛剛仔細想想,並且在與kk同學的討論中,把程式改進了一下,如下:

char* DeleteFun1(char* str)
{
	int times[256];
	//memset(times, 0, 256 * sizeof(int));
	memset(times, 0, sizeof(times));

	char *p = str;
	char *q = str;
	while (*p != '\0')
	{
		if (times[*p] != 0)
		{
			p++;
		}
		else
		{
			times[*p] = 1;
			*q = *p;
			p++;
			q++;
		}
	}
	*q = '\0';
	return str;
}
幾點思考:

(1)出現次數陣列大小為256,可以容納所有的大小寫字母和特殊字元;

(2)初始化使用memset,比用for迴圈效率高,而且寫得更簡單;

(3)只要用一個迴圈即可,即掃描的時候即判斷這個字元是否是出現了,如果沒有出現則留下這個字元,如果已經出現了則直接pass掉;

(4)不用加index這個變數,也不用做操作*p - 'a',可以直接用*p來作下標(因為開了256大小的陣列);

(5)sizeof(times)的大小和256 * sizeof(int)的大小是一樣的。