Leetcode解題思路總結(Medium)

338. Counting Bits

思路:計算一個10進制數的2進製表示中含有多少個1,有2種方法,一種是bit manipulation,另一種是簡單的dynamic programming。代碼見:http://www.cnblogs.com/coderworld/p/leetcode-countingbits.html

136. Single Number

思路:一個數組中,每個數字都出現了2次,只有一個數字出現了1次,要求找到那個數。我一開始想到的方法是用掃描數組添加到set中,如果出現了2次就從set中erase掉,掃面完後set中唯一一個元素就是我們需要的返回值,寫完代碼AC結果發現要84ms,超級慢。然後我在搜了搜,發現有種20ms就AC的方法,那就是利用異或操作^,a^a=0, a^0=a,根據交換律a^b=b^a,比如3^4^3=4,根據異或操作的這種性質,我們可以將所有元素依次做異或操作,相同元素異或爲0,最終剩下的元素就爲Single Number。時間複雜度O(n),空間複雜度O(1)。代碼見我

347. Top K Frequent Elements

思路:找出一個數組中出現次數最多的K個數。可以考慮用priority_queue,假如元素是<int, int>這種pair形式,那麼優先隊列就是按着key的降序進行的,所以隊首一定是key最大的元素。這樣從優先隊列中pop出前K個元素,就可以得到結果了。不過問題是怎樣把數組中的元素加到優先隊列中。所以我們需要對數組做一次預處理,即統計每個數字出現的次數。可以用map,但是我選擇用unordered_map,因爲unordered_map是無序的,map是有序的,所以插入元素時unordered_map會快很多。最後代碼運行36ms 如果用map的話,那就是60ms了。

260. Single Number III

思路:前面做了只有一個出現一次的數,其他都是出現兩次,思路和那題一樣。只是這個先將所有數一起異或,然後得到的結果將是兩個只出現一次數的異或。也就是說最後得到的數字是a ^ b,而我們需要的是a和b而不是a和b的異或。那如何將a和b從(a^b)中分離呢?比如a是5(101),b是3(011),那麼(a^b)就是6(110),觀察一下6,6的第二位爲1說明a和b在第二位肯定不同,然後就可以根據與這個位的數是否爲0將數組分爲兩半,並且a和b肯定會被分別分開到這兩個數組中。這樣問題就回到了上題的思路,只要讓子數組內元素全部異或一下,得到的兩個數就是最終要的只出現一次的數。這段話可能有點繞,需要好好琢磨琢磨一下。判斷1在哪一位就用0x01循環的去做&運算就好。代碼只需要16ms

238. Product of Array Except Self

思路:解法比較巧妙。由於output[i] = (x0 * x1 * ... * xi-1) * (xi+1 * .... * xn-1)。因此執行兩趟循環:
第一趟正向遍歷數組,計算x0 ~ xi-1的乘積
第二趟反向遍歷數組,計算xi+1 ~ xn-1的乘積

運行時間64ms

122. Best Time to Buy and Sell Stock II

思路:解法比較巧妙。題目說明可以多次買賣,但是同一時間只能有一股在手裏。 這樣就可以在每次上升子序列之前買入,在上升子序列結束的時候賣出。相當於能夠獲得所有的上升子序列的收益。 而且,對於一個上升子序列,比如:5,1,2,3,4,0 中的1,2,3,4序列來說,

對於兩種操作方案: 

一,在1買入,4賣出; 

二,在1買入,2賣出同時買入,3賣出同時買入,4賣出; 

這兩種操作下,收益是一樣的。 所以算法就是:從頭到尾掃描prices,如果i比i-1大,那麼price[i] – price[i-1]就可以計入最後的收益中。這樣掃描一次O(n)就可以獲得最大收益了。

運行時間爲8ms

319. Bulb Switcher

思路:這是一道數學題。大概解釋一下,當一個燈泡被執行偶數次switch操作時它是關着的,當被執行奇數次switch操作時它是開着的,那麼這題就是要找出哪些編號的燈泡會被執行奇數次操作。將燈泡編號爲1到n,第i個燈泡會在第d輪被switch,當且僅當d能整除i(i % d == 0)。所以第i個燈泡只有當switch了奇數次後,它纔會亮着。

而一個數的質因數是成對存在的。比如12,它能被1、12、2、6、3、4整除,並且12被switch了偶數次,所以最後還是滅着的。所以問題就轉變成了求一個數的質因子數有多少個。再來看下36,36有質因數1、36、2、18、3、12、4、9.還有2個6.所以它的distinct的質因數是奇數個,它最後會亮着。

可以發現規律,只有當i它是一個平方數的時候,第i個燈泡最後會亮。所以問題就變成了求1到n範圍內的平方數有多少個。

所以直接用sqrt(n),就可以求出1到n範圍內的平方數的數目了。這道題真是考數學和智商啊23333

343. Integer Break

思路:一個數,把它分爲至少2個數的和的形式,然後求分解的各個數的乘積的最大值。比如9=3+3+3,9=4+5.但是3*3*3=27是大於4+5的,所以最後返回27.這道題也是一道數學找規律題。可以嘗試着手寫2到12之間的數字。然後發現的規律就是把每個數分解爲3+3+···+2+···+2的形式是最優的。並且3的數目要儘量的多,只有當不能取夠3的時候,再去取2.代碼可見:0ms

268. Missing Number

思路:求一個數組中少了哪個數,比如[0,1,3]裏面少了2,數組裏的數都是distinct的,數組的長度如果是3,那麼就從0到3裏挑3個數存入數組,然後讓你找少了哪個數。有2種方法可以AC。

第一種是數學方法:可以先求0到n的和,然後求數組的sum,然後把他們一相減,得到的數字就是答案。運行時間32ms

第二種是bit位操作:利用異或的性質。把數組裏的每個數和下標以及數組長度連環做異或。那麼得到的就是答案。運行時間36ms

比如0^1^3 ^0^1^2^3 = 2,2就是缺少的那個數,也就是答案。

144. Binary Tree Preorder Traversal

思路:二叉樹先根遍歷。有遞歸和非遞歸2種方式,遞歸很簡單:0ms

非遞歸就是利用一個stack,不過記得每次是先把右節點push進來,然後再push左節點。時間也是0ms

318. Maximum Product of Word Lengths

思路:在一個字符串組成的數組words中,找出max{Length(words[i]) * Length(words[j]) },其中words[i]和words[j]中沒有相同的字母。

方法就是先把每一個單詞編碼爲26位的二進制數,比如abcd就是00000000000000000000001111,abce就是00000000000000000000010111。然後,兩兩之間互相比較,如果位與運算爲0,則說明兩者沒有共同字母,則可以進行乘法。然後在這兩層循環的過程中不斷更新最大值,循環結束後就得到返回值了。時間複雜度爲O(n*n)。運行時間爲128ms

94. Binary Tree Inorder Traversal

思路:二叉樹中序遍歷。有遞歸和非遞歸2種方式,遞歸很簡單:3ms

非遞歸就是利用一個stack,對於任一結點P,

1)若其左孩子不爲空,則將P入棧並將P的左孩子置爲當前的P,然後對當前結點P再進行相同的處理; 

2)若其左孩子爲空,則取棧頂元素並進行出棧操作,訪問該棧頂結點,然後將當前的P置爲棧頂結點的右孩子; 

3)直到P爲NULL並且棧爲空則遍歷結束

時間0ms

可參考:http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html

12. Integer to Roman

思路:整數轉換爲羅馬數字。分析羅馬數字的規律。就把羅馬數字和對應的整數存入數組,然後逐個循環遍歷。

我們現在拿到一個數N 我們就去表裏面找不超過它的最大的數x, 然後把它入我們的輸出字符串中,然後將數N-=x, 繼續執行這個操作,直到N=0。運行時間32ms

230. Kth Smallest Element in a BST

思路:求二叉查找樹的第k個最小元素。注意到二叉查找樹的中序遍歷結果是有序的,可以利用這個性質來輸出結果。用遞歸的方法做24ms

137. Single Number II

思路:一個數組中,除了一個數之外,其他全部元素都出現了3次,找出那個數。我用的很簡單暴力的方法,就是先直接全部存入unordered_map中(因爲不用排序,比map要快),key是每個元素的值,value是每個元素出現的次數。然後再遍歷整個map,找出value不爲3的元素,返回就是答案了,運行28ms  還有一種是位運算,但是我沒搞懂,希望有大神能給我講解一下

96. Unique Binary Search Trees

思路:一個典型的動態規劃題,後面的計算依賴於前面產生的結果。假如當前根節點是A,則這棵樹的二叉樹的數目爲#(左子樹)×#(右子樹),而根據二叉查找樹的規律,左子樹跟右子樹是互相沒有交集的,並且左子樹的任意元素的值都要小於右子樹的任意元素的值。以一個count數組來表示共有i個節點時,能產生的BST樹的個數。

n == 0 時,count(0) = 1,

n == 1 時,count(1) = 1,因爲只有1這個根節點,數量也爲1。

n == 2 時,分2種情況考慮,一種是根爲1,另一種是根爲2.

n = 2; 1__ __2  

\ /  

count[1] count[1]  

count(2) = count(0) × count(1) + count(1) × count(0) = 2

n == 3 時,分3種情況考慮,根分別爲1、2、3,

count(3) = count(0) × count(2) + count(1) × count(1) + count(2) × count(0) = 5

同時,當根節點元素爲 1, 2, 3, 4, 5, ..., i, ..., n時,基於以下原則的BST樹具有唯一性: 以i爲根節點時,其左子樹構成爲[0,...,i-1],其右子樹構成爲[i+1,...,n]構成 

因此,count[i] = sigma(count[0...k] × count[k+1...i]) 0 <= k < i - 1

所以只要找到規律,就能0ms通過

35. Search Insert Position

思路:二分查找,但是需要變下型,因爲其實這個問題是等價於找lower bound,所以每次就把left+1,9ms

108. Convert Sorted Array to Binary Search Tree

思路:把一個有序數組轉換爲平衡二叉搜索樹。還是用二分查找遞歸構造,每次選擇中點作爲root,然後左子樹就遞歸的用左半邊數組,右子樹就遞歸的用右半邊數組。運行時間20ms

337. House Robber III

思路:https://leetcode.com/discuss/91899/step-by-step-tackling-of-the-problem

22. Generate Parentheses

思路:見CC150的9.6

78. Subsets

思路:詳見:http://www.cnblogs.com/felixfang/p/3775712.html  遞歸的話可以參考九章算法的模板

90. Subsets II

思路:同上

46. Permutations

思路:最簡單的是用C++的next_permutation函數去實現,記得先排序一下。12ms過。此外,自己實現的話,有遞歸和迭代兩種方式,細細觀察,可以從頭開始找規律。

47. Permutations II

思路:受到這個解法的啓發,以及這個博客的4種生成全排列的算法。這道題也可以用C++的next_permutation函數去AC過。我還是選擇了用全排列樹去AC,不過注意的是,如果2個需要交換的數相等的話或者要交換的數已經在set中,就不用交換了。40ms過的

74. Search a 2D Matrix

思路:二維數組裏進行二分查找,記得用下標把二維轉換爲一維,此外注意以下幾點,否則會造成死循環:記得在外層循環的判斷條件裏寫left <= right,如果寫的是left < right的話,就不會到達最右邊的值。然後記得每次二分後left = mid +1 和right = mid - 1。1ms




發佈了101 篇原創文章 · 獲贊 39 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章