LeetCode刷題 --雜篇 --數組,鏈表,棧,隊列

  武漢加油,中國加油。但願疫情早日結束。面試

  因爲疫情,二狗寒假在家不能處處亂逛,索性就在家裏系統的刷一下算法的內容,一段時間下來倒也有些小小的收穫。只是一來家中的小破筆記本寫起博客來實在不是很順手,二來家中吃喝玩樂的誘惑也很多了,就連着幾天沒有更新,慚愧慚愧。看來2020年仍是要增強本身計劃的執行能力。算法

  每一個人都有適合本身的學習方式。雖然也挺喜歡看書,但對我來講,在學習新內容,不熟悉的內容的時候單純的啃課本仍是有些事倍功半,尤爲是像算法這種這麼容易看得一臉懵逼的內容。大名鼎鼎的《算法導論》買回來了挺長時間了,只看了感興趣的幾章,而且在看得時候常常懷疑本身,我是否是腦子不行啊,要不轉行算了(苦笑)。基於以前學習數據庫的經驗,趁着寒假整了個算法的音頻課程聽了一下,感受還不錯,恩,看來我比較適合這種方式吧。之後再要學習什麼新東西的時候記得提醒本身,先選對了學習的方式哈。數據庫

  女友問我,算法是什麼,學這個有啥用? 其實以前我也沒有想明白,最開始從leetcode刷題目的很簡單,多長點見識,萬一面試用上了呢。因此女友這麼問的時候我就隨口一胡扯:武功知道吧,以前的實戰經驗算是身法,這玩意兒(算法)是心法。如今對這個抖機靈的回答還有點小驕傲,我還挺機智的呀。可不是嘛,各類常見的數據結構,常見的算法,各大高級語言都幫咱們實現好了,你們平常「CRUD」哪裏用得上這些啊?但其實也不對,好比兩種數據結構均可以作的時候,哪一種更合適呢?若是想效率更高呢?若是必需要在限制的空間內完成呢?或者接地氣一點:和同事關於內容battle的時候,怎麼優雅地說服他呢?數組

來點乾貨:安全

  反正博客寫給本身看,記錄一下這兩天筆記中讓我有耳目一新的感受的內容吧。數據結構

  數組:函數

  • 數組是一種線性表數據結構。它用一組連續的內存空間,存儲一組具備相同類型的數據,最大的特色是支持隨機訪問
  • 根據下標來隨機訪問數組中的元素,因此數組這種結構的」查找「其實很高效。
  • 又由於它是連續存儲的,因此相對來講,」插入「和」刪除「這兩個操做會比較低效。由於這兩個操做頗有可能使得數組內大量元素從新移動位置。
  • 由於是連續的內存空間,因此若是內存中剩下一個40m的內存塊,一個60m的內存塊,實際上是沒法申請一個80m大小的數組的。可是鏈表能夠。

  鏈表:性能

  • 與數組相反,鏈表不須要連續的內存,它經過」指針「來將一組零散的內存塊串起來使用。因此上面數組中的那種狀況,鏈表是能夠完成的。
  • 相對數組來講,鏈表的」插入「和」刪除「會高效不少,畢竟只要改變相關聯的指針的指向便可。

  這兩種數據結構實在是太基礎了,基礎到基本不會用到。拿二狗子來講,若是有相似的東西須要實現的話我會怎麼作呢,我會申請一個List出來,剩下的都交給List去作了。但看看上面兩中數據結構的比較,其實差異仍是挺大的。而關於List,寫這篇博客的時候我又去微軟官方文檔瞅了一眼:學習

  • List<T>類是 ArrayList<T>類的泛型等效項。 它經過使用大小根據須要動態增長的數組來實現IList<T>泛型接口。
  • 在決定是使用List<T> 仍是 ArrayList類(二者都具備相似的功能)時,請記住List<T> 類在大多數狀況下性能更佳而且是類型安全的。 若是引用類型用於 List<T>類的類型 T,則這兩個類的行爲是相同的。 可是,若是將值類型用於類型 T,則須要考慮實現和裝箱問題。spa

  • 若是值類型用於類型 T,則編譯器將爲該值類型專門生成 List<T>類的實現。 這意味着,在使用元素以前,不須要對 List<T>對象的 list 元素進行裝箱,在建立了大約500個列表元素後,不會對其進行裝箱的內存列表元素大於用於生成類實現的內存。

  看來,List應該是用數組來實現的,而且.net有一些特殊的處理使得這傢伙既安全,又高效。至於第三條,看來若是要存儲的是值類型的數據,而且數據量較多的狀況下仍是使用List比較高效。另外微軟也是建議你們儘可能使用List而不是本身手動實現,緣由以下:

  使用 List<T> 類的特定於類型的實現,而不是使用 ArrayList類或自行編寫強類型包裝集合,這一點很是有利。 緣由在於,你的實現必須執行 .NET Framework 的操做,而且公共語言運行時能夠共享你的實現不能的 Microsoft 中間語言代碼和元數據。

 

  棧

  後進者先出,先進者後出,是一種」操做受限「的線性表。

  隊列

  先入隊列的先出隊列,後入的後出。一樣,隊列也是一種」操做受限「的線性表。

  這兩種數據機構也很常見,新的發現是在作練習時遇到了這樣一道題,怎麼用棧來實現一個隊列,題目不難,可是挺有趣的。貼一下題目與筆者的作法,題目來源於Leetcode。

232. 使用棧實現隊列的下列操做:

push(x) -- 將一個元素放入隊列的尾部。
pop() -- 從隊列首部移除元素。
peek() -- 返回隊列首部的元素。
empty() -- 返回隊列是否爲空。
示例:

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false
說明:

你只能使用標準的棧操做 -- 也就是隻有 push to top, peek/pop from top, size, 和 is empty 操做是合法的。
你所使用的語言也許不支持棧。你可使用 list 或者 deque(雙端隊列)來模擬一個棧,只要是標準的棧操做便可。
假設全部操做都是有效的 (例如,一個空的隊列不會調用 pop 或者 peek 操做)。

 1     public class MyQueue
 2     {
 3         private Stack<int> stack1;
 4         private Stack<int> stack2;
 5 
 6         /** Initialize your data structure here. */
 7         public MyQueue()
 8         {
 9             stack1 = new Stack<int>();
10             stack2 = new Stack<int>();
11         }
12 
13         /** Push element x to the back of queue. */
14         public void Push(int x)
15         {
16             if(stack1.Count > 0 ||(stack1.Count == 0 && stack2.Count == 0))
17             {
18                 stack1.Push(x);
19             }
20             else
21             {
22                 while(stack2.Count > 0)
23                 {
24                     stack1.Push(stack2.Pop());
25                 }
26 
27                 stack1.Push(x);
28             }
29         }
30 
31         /** Removes the element from in front of queue and returns that element. */
32         public int Pop()
33         {
34             if (stack1.Count > 0)
35             {
36                 while (stack1.Count > 0)
37                 {
38                     stack2.Push(stack1.Pop());
39                 }
40             }
41 
42             return stack2.Pop();
43         }
44 
45         /** Get the front element. */
46         public int Peek()
47         {
48             if (stack1.Count > 0)
49             {
50                 while (stack1.Count > 0)
51                 {
52                     stack2.Push(stack1.Pop());
53                 }
54             }
55 
56             return stack2.Peek();
57         }
58 
59         /** Returns whether the queue is empty. */
60         public bool Empty()
61         {
62             return (stack1.Count == 0 && stack2.Count == 0);
63         }
64     }

  上面的作法還行,思路是利用兩個棧來進行實現。而想到這個方法時實際上是有點小開心的,有點靈機一動的快感,哈哈。隊列中的入隊操做會將一個元素添加到隊列中去,而這個隊列會在當前隊列中全部元素都出隊以後纔會被訪問到。而棧呢,若是不向棧中添加新的元素,那麼下一次出棧操做就會把這個元素給pop出來。所以很容易聯想到用兩個棧來實現,當須要出隊列的時候,咱們就把棧中的元素依次pop,並push到另外一個棧中,這樣最早進入棧中的元素反而就到了棧頂。剩下的就和隊列很相似了。

  其實算法的學習中還有不少」相似「的狀況,但前提是你要了解兩種不一樣數據結構的特色與做用。優點是什麼,劣勢是什麼。而數據結構與算法也不是孤立的,好比你們都瞭解的各類排序,如插入排序,冒泡排序,快速排序等等都不是單一孤立使用的。好比各大高級語言的集合類通常都會提供排序方法,做爲碼農咱們直接拿來主義就可使用了。但其實它們內部是會根據不一樣的數據量啊,大小等進行不一樣的處理,調用不一樣的算法來進行實現的。這些其實也都挺有意思的。

 

附加一道題目:

  這道題其實感受有些相似與腦筋急轉彎,啓發是有時候多是咱們沒有按照計算機的方式去思考,反而複雜化了。反正筆者看這道題的解法和歡樂多的網友相似----原來我是個傻子,哈哈。Leetcode第6題:

將一個給定字符串根據給定的行數,以從上往下、從左到右進行 Z 字形排列。

好比輸入字符串爲 "LEETCODEISHIRING" 行數爲 3 時,排列以下:

L C I R
E T O E S I I G
E D H N
以後,你的輸出須要從左往右逐行讀取,產生出一個新的字符串,好比:"LCIRETOESIIGEDHN"。

請你實現這個將字符串進行指定行數變換的函數:

string convert(string s, int numRows);
示例 1:

輸入: s = "LEETCODEISHIRING", numRows = 3
輸出: "LCIRETOESIIGEDHN"
示例 2:

輸入: s = "LEETCODEISHIRING", numRows = 4
輸出: "LDREOEIIECIHNTSG"
解釋:

L D R
E O E I I
E C I H N
T S G

public class Solution {
        public string Convert(string s, int numRows)
        {
            if(numRows == 1)
            {
                return s;
            }

            var charArray = s.ToCharArray();

            string[] resultList = new string[Math.Min(charArray.Length, numRows)];

            int currentRow = 0;
            bool goDown = false;

            for (int i = 0; i < charArray.Length; i++)
            {
                resultList[currentRow] = resultList[currentRow] + charArray[i];

                if (currentRow == 0 || currentRow == numRows - 1)
                {
                    goDown = !goDown;
                }

                currentRow = goDown ? currentRow + 1 : currentRow - 1;
            }

            string result = string.Empty;

            for (int i = 0; i < resultList.Length; i++)
            {
                result += resultList[i];
            }

            return result;
        }
}

  官方的解法傳送門在這裏, 傳送門

  我本來的思路是如何把字符串處理成想要的格式,而後再依次輸出。可是看了高手的解答真的很驚喜,何須這樣呢,其實咱們更簡單一些,所見即所得的輸出很差嘛,每行看到的是什麼就把什麼輸出就行了,總之感受十分奇妙。

  

  這兩天還看了一些二分法和樹的內容,可是還沒找些題練練手,晚些再水一篇博客把,嘿嘿。

  另外,但願疫情早點結束,你們的生活回到正規,感謝在一線奮戰的醫務工做者們。

相關文章
相關標籤/搜索