前後重組字符串

        距離上次寫博客已經快一個月了,最近這個月都一直在忙着找工作,現在暫時有了一個offer,剛好昨天去網易筆試了一下,就將裏面的題目拿出來做做。

        題目是這樣子的:輸入一個字符串src,從這個字符串去除頭或者尾一個字符,並將這個字符加到另外一個字符串result的尾端,刪除了src的所有字符後,要求得到最後的字符串result最小(即要求字符串是生成的字符串是按字符字典最小的字符串),例如輸入 src="acdebcb",輸出爲result="abcbcde"。

        其實題目的意思就是前後不斷地取src字符串的字符元素,小的那個先取。題目不是很難,關鍵步驟是看怎麼去處理當前後字符相等時的情況。(剛開始以爲自己的思路是正確的,結果在寫這篇博客分析的時候,卻發現邏輯有點不對,於是又重新想了下,看來寫博客也有這方面的好處啊

        我的思路是這樣子的,先設置兩個下標變量front和把back分別指向字符串的頭和尾,如下圖所示:


        看src[front]和src[back]哪個小,小的那個就將其加到result中,並且下標變量更新。

        如果相等,就再設置兩個臨時變量left和right,分別指向相等的前後兩個元素,並調用函數去判斷是從字符串的左邊還是右邊去取數。一開始以爲要用遞歸去判斷多重相等的情況,所以就寫成函數的形式,後面調試的時候發現是不用遞歸的,結果後面還是保留了函數的形式,不過這樣子看也不錯,能把邏輯分開來,好懂一些。

        函數 findIndex 是個邏輯判斷函數,首先是處理下標left和right,front和back 的越界情況,然後是多個判斷情況。

        1.判斷下兩個元素,即left和right對應的元素是不是比前面的元素都大,是的話,就返回左邊或者右邊都可以,這裏是返回左邊,記得要將left值要減一。

        2.判斷如果src[left]不等於src[right]且有一個小於它對應的前一位的值,那麼就返回小的值的那一端。

        3.判斷如果src[left]等於src[right]且它們小於它的前一位值,那麼就循環更新left和right的值。當循環結束時,要考慮是哪個條件導致了循環結束,於是又分爲了下面幾種情況:

        (1)如果是下標條件越界的,就就隨便返回一邊,這裏是返回左邊,記得將left減一,因爲之前是越界了。

        (2)這裏說明沒有越界,然後判斷左右是不是相等,如果有小的一端,那麼就返回小的那個方向,如果沒有小的一端,說明這兩個元素相等而且大於前面的元素,那麼情況就和前面的情況1是一樣的,直接返回一邊即可(下標要處理)。

        到這裏好像就討論完了,其實還要處理最後一個當left等於right的時候,那麼也要將最後一個元素加到字符串的後面去,那麼現在就是真正的結束了。

        下面是代碼,代碼裏面有註釋,對應了上面的的分析。可以參照着代碼和分析一起看,這樣可能容易懂一些。測試了多個用例,感覺是對的,但不保證完全沒有錯誤。另外,這是網易筆試題第一道編程題,感覺是不是應該有更簡單的分析方法呢,如果大家有的話歡迎來交流。

//返回值 0代表左邊,1代表右邊
int findIndex(const std::string& src,int& front,int& back,int& left,int& right)
{
	if (front > back || left > right)
	{
		return 0;
	}

	//如果下兩個元素都比前面的元素大,那麼前面的兩個元素加到目標字符串的尾部
	if (left < right && src[left] > src[front] && src[right] > src[back])
	{
		left--;
		return 0;	
	}

	//如果left和right不相等,而且有一個小於front的元素,那麼就將小的那一端的兩個元素加到目標字符串尾部
	if (left < right && (src[left] < src[front] || src[right] < src[back]) && src[left] != src[right])
	{
		if (src[left] < src[right])
		{
			return 0;
		}
		else if (src[left] > src[right])
		{
			return 1;
		}		
	}

	//如果left和right一直相等而且都是小於前一個數的話,就一直循環,直到下標結束條件或者left和right對應的元素值大於前一個值
	while(left < right && src[left] == src[right] && src[left] < src[left-1])
	{
		left++;
		right--;
	}

	//判斷是不是下標條件結束的
	if (left >= right)
	{
		left--;
		return 0;
	} 
	else
	{
		//判斷左右是不是還相等
		if (src[left] < src[right])
		{
			return 0;
		} 
		else if(src[left] > src[right])
		{
			return 1;
		}
		else
		{
			//左右還相等的話,到這裏,就說明 src[left] >= src[left-1] && src[left] == src[right],
			//那麼就遞歸求值
			/*left++;
			right--;
			return findIndex(src,front,back,left,right);*/
			
			//不用遞歸,直接返回之前的下標即可
			left--;
			return 0;
		}
	}
}

std::string ResortString(const std::string src)
{
	string result;

	int len = src.length();

	if (len < 1)
	{
		return result;
	}
	else if (1 == len)
	{
		result = src;
		return result;
	}

	int front = 0,back = len-1;

	//兩個下標分別標記字符串的頭部和尾部
	while (front < back)
	{
		//小的那個字符加到結果字符串中
		if (src[front] < src[back])
		{
			result += src[front++];
		}
		else if (src[front] > src[back])
		{
			result += src[back--];
		} 
		else	
		{
			//如果兩個元素相等,則另外設兩個標誌下標
			int left = front +1;
			int right = back -1;

			//調用函數去判斷是從左邊還是右邊取數
			int direct = findIndex(src,front,back,left,right);
			
			if (!direct)
			{
				//左邊取數
				while(front <= left)
				{
					result += src[front++];
				}
			} 
			else
			{
				//右邊取數
				while(back >= right)
				{
					result += src[back--];
				}
			}

		}
	}

	//考慮下標相等的情況
	if (front == back)
	{
		result += src[front];
	}


	return result;
}


//

int main()
{
	string str = "acdebcb";	//acbdegfadbcb	aedcezecdea	baezeab	acbdadbcb

	cout<<ResortString(str)<<endl;

	cout<<"end"<<endl;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章