劍指offer之從尾到頭打印鏈表(最淺顯易懂)

從尾到頭打印鏈表 之 “C++代碼+思路解析 ”

下一篇 從尾到頭打印鏈表 (第二種情況 允許原地打印鏈表)

希望我的文字始終給您帶來畫面感。

其實做算法題的過程也是在考驗我們的大腦日常解決問題的能力,懂不懂得將生活中碰到的難題拆分,一一解決

今日感悟

做算法題不要過分依賴於自己舊的的知識庫,獨立的把它看做一道新鮮的算法題。千萬不要一碰到陌生的知識點就丟失信心。做新的算法題一定會涉及到不熟悉的數據結構知識和語法問題,把它當做工具先使用,有時間的話再去了解它是什麼,不要在認識它的本質上浪費一分一秒的時間。

題目開始咯!

  題目描述:輸入一個鏈表,按鏈表值從尾到頭的順序返回一個ArrayList。

//這裏敲黑板,千萬注意:我們做算法題 ,最基本的也是最關鍵的題目一定要 理解準確。這道題涉及到允不允許原地修改鏈表,所以分爲以下兩種情況。

 第一種情況:不允許原地修改鏈表,如果不允許原地修改鏈表,
 那麼可以利用棧後進先出的特點,遍歷鏈表,逐個將鏈表元素放入棧中,
 然後依次彈出棧頂元素並打印。

代碼實現部分:

//5月8日
struct ListNode {
	int val;
	struct ListNode* next;
	ListNode(int x) :
		val(x), next(NULL) {
	}//這裏不懂爲什麼這麼寫,沒關係
};
class Solution {
public:
	vector<int> printListFromTailToHead( ListNode* head ){
		vector<int> res;
		if ( !head )
			return res;
		//我寫代碼定義一般先不寫,後面需要用到就把它加上。
		stack<int> sta;    
		ListNode* p = head;//指針就記着在內存裏面給這個變量p分配一塊地址,跟變量一樣使用。
		while ( p )
		{
			sta.push( p->val );//循環裏面最關鍵的是push這個動作
			p = p->next;
		}
		while ( !sta.empty() )
		{
			int a = sta.top();
			sta.pop();
			res.push_back(a);
		}

		return res;
   }
};

思路解析部分:

我不知道大家的寫算法思路是思維習慣和先後順序是怎樣的,我會習慣將代碼拆分成小的代碼塊進行 ,再進行邏輯組合安裝。當然這裏無法評判哪種一定是正確的,這裏我想分享一下:我個人認爲最快的寫代碼順序。

第一步:我會先搞清楚題目 ,需要我給它一個什麼,定下來整體的框架。

比如這道題它要我給它返回一個 數組。一個裝着鏈表中倒序值的數組。那麼 返回值類型返回語句
心裏就有個概念了。還要搞清楚我們這道題需要的數組選擇用靜態的還是動態,動態就用vector

那第一步函數整體的框架就出來咯!

vector< int > printListFromTailToHead(..........{
vector< int > res;
................................
return res;
}

第二步:我會把參數定下來,進到函數體首先就檢查參數合不合法。

加入 if 語句檢驗參數 鏈表指針 head 是否爲空。

vector< int > printListFromTailToHead( ListNode* head ){
vector< int > res;
//加入這塊代碼檢驗參數。
if( !head )
{
 return res;
}
................................
return res;
}

第三步:給框架裏面填上語句塊。發揮( if,while,for…)語句的作用,語句其實就是思考邏輯的實現。

這道題的邏輯就是把鏈表的數值一個一個倒進棧裏,再從棧一個一個倒入新的容器裏,拿到這個容器就OK了。

1 填入 這塊代碼,使用while 語句,把鏈表裏的值一個一個推到棧裏。

vector< int > printListFromTailToHead( ListNode* head ){
vector< int > res;
if( !head )
{
 return res;
}
//加入這塊代碼向棧裏推數值
...............................//這裏要加定義
while ( p )
{
    sta.push( p->val );//循環裏面最關鍵的是push這個動作
	p = p->next;
}

................................
return res;
}


2 再填入一塊代碼,繼續使用while語句,把棧裏的值一個一個彈出來,再一個一個推到容器裏面。

vector< int > printListFromTailToHead( ListNode* head ){
vector< int > res;
if( !head )
{
 return res;
}
//加入這塊代碼向棧裏推數值
...............................//這裏要加定義
while ( p )
{
    sta.push( p->val );//循環裏面最關鍵的是push這個動作
	p = p->next;
}
//加入這塊代碼,把棧裏的值一個一個彈出來,再一個一個推到容器裏面。
while ( !sta.empty() )
		{
			int a = sta.top();
			sta.pop();
			res.push_back(a);
		}
return res;
}

第四步:摳細節,扣語句塊裏的細節,沒定義的變量要給定義。對象要使用什麼函數來實現,組裝起來。

1 給對象加上定義。

while ( p )
{
    sta.push( p->val );//循環裏面最關鍵的是push這個動作
	p = p->next;
}

while語句循環檢驗的這個指針p ,要在前面加上定義。
sta 是一個棧變量,它是一個數據的臨時存放容器,繼續補上定義。

ListNode* p = head;
stack<int> sta;  

這就知道了p指向的是傳進來的鏈表head的頭結點,sta是一個棧變量。

2 使用函數 top() ,pop(), push_back(),也就是組裝動作。

while ( !sta.empty() )
		{
			int a = sta.top();
			sta.pop();
			res.push_back(a);
		}

總結:

我做算法題是先搞清楚題意,安排總框架,然後把解決辦法拆分成一個個步驟,再把每個步驟落實到代碼塊,最後填充細節。

這樣可以保證算法題做下來的整個過程中我們的整個思路是清晰的,不會讓看似複雜的算法在我們的大腦中留下壞印象,使我們喪失興趣。

其實做算法題的過程也是在考驗我們的大腦日常解決問題的能力,懂不懂得將生活中碰到的難題拆分,一一解決。

下一篇 從尾到頭打印鏈表(第二種情況 允許原地打印鏈表)

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