算法1

這里是我算法練習(xí)的一些例子叹括,當(dāng)作思維訓(xùn)練,題目來(lái)主要來(lái)自自劍指offer宵荒,我用python作為實(shí)現(xiàn)語(yǔ)言汁雷,個(gè)別可能沒(méi)有測(cè)試完整的,歡迎通過(guò)簡(jiǎn)書(shū)交流

二維數(shù)組查找

描述:在二維數(shù)組中报咳,每一行按照從左到右遞增摔竿,每一列按照從上到下遞增,輸入一個(gè)這樣的二維數(shù)組(1)少孝,和一個(gè)整數(shù)7,找到這個(gè)整數(shù)返回 True, 否則 False

1 2 8 9

2 4 9 12

4 7 10 13

思路1: 最原始的想法當(dāng)然是遍歷所有的元素,復(fù)雜度是 O(n^2)

思路2: 選取右上角的數(shù)字(其實(shí)左下角也可以)熬苍,然后比較與數(shù)字7的大小稍走,如果等于,查找過(guò)程結(jié)束柴底;如果大于婿脸,就刪除整個(gè)列;如果小于柄驻,就刪除整個(gè)行, 復(fù)雜度O(n)$狐树。

簡(jiǎn)潔易懂,下面是我的python實(shí)現(xiàn):

def find_num(matrix, num):
    ct = 0
    for cols in matrix[::-1]:
        for col in cols[ct:]:
            if col == num:
                return True
            elif col > num:
                break  # 刪除一列
            else:
                ct += 1  # 刪除一行
                continue

# test
if __name__ == "__main__":
    m = [[1, 2, 3, 6],[2, 4, 7, 8],[8, 9, 10, 11],[9, 12, 13, 15]]
    n = 7
    find_num(m, n)

從尾到頭打印鏈表

鏈表實(shí)現(xiàn):使用tuple表示一個(gè)Node

思路1: 遍歷鏈表鸿脓,存到棧里面抑钟,然后輸出棧, 但其實(shí)我們不用手動(dòng)實(shí)現(xiàn)棧野哭,直接用遞歸函數(shù)就可以了

貌似過(guò)于簡(jiǎn)單了:)

def print_rlt(lt):  # lt: linked_table
    if lt[1] is not None:
        print_rlt(lt[1])
    print lt[0]


# test
if __name__ == "__main__":
    # a node => (val, next) 
    linked_table = (1, (2, (3, (4, None))))
    print_rlt(linked_table)

思路2:上面的算法可以進(jìn)行優(yōu)化在塔,遞歸函數(shù)在數(shù)據(jù)量大的時(shí)候會(huì)導(dǎo)致棧溢出, 可以用循環(huán)代替拨黔,或者尾遞歸優(yōu)化(就是保證函數(shù)的最后一步是調(diào)用自身)蛔溃,但是python不支持尾遞歸優(yōu)化,而且永遠(yuǎn)不會(huì)支持,java也是不支持的贺待,尾遞歸優(yōu)化貌似只在函數(shù)式語(yǔ)言中支持的比較好徽曲,但神奇的是es6在開(kāi)啟嚴(yán)格模式下是支持的

重建二叉樹(shù)

描述:根據(jù)二叉樹(shù)的前序遍歷麸塞,中序遍歷 重建整個(gè)二叉樹(shù)

思路:還是遞歸秃臣,前序的第一個(gè)元素就是root, 根據(jù)root我們可以找到中序左子樹(shù), 中序右子樹(shù)喘垂;然后找到前序左子樹(shù)甜刻,前序右子樹(shù);遞歸找下去… 還是看代碼吧

def rebuild(preorder, inorder):
    if not preorder:
        return None
    root_val = preorder[0]
    root_index = inorder.index(root_val)

    inorder_left = inorder[:root_index]
    inorder_right = inorder[root_index + 1:]

    preorder_left = preorder[1:len(inorder_left) + 1]
    preorder_right = preorder[len(inorder_left) + 1:]

    left = rebuild(preorder_left, inorder_left)   # 遞歸構(gòu)建左子樹(shù)
    right = rebuild(preorder_right, inorder_right)  # 遞歸構(gòu)建右子樹(shù)
    root = (left, root_val, right)
    return root


# test
if __name__ == "__main__":
    # a node => (left, val, right)
    a = [1, 2, 4, 7, 3, 5, 6, 8]
    b = [4, 7, 2, 1, 5, 3, 8, 6]
    print rebuild(a, b)

用兩個(gè)棧實(shí)現(xiàn)隊(duì)列

描述:用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列

思路:維護(hù)兩個(gè)棧正勒,棧1負(fù)責(zé)插入操作得院,棧2負(fù)責(zé)刪除操作,當(dāng)棧2為空時(shí)章贞,將棧1的元素都推到棧2里面

class Queue(object):
    stack1 = []
    stack2 = []

    def append_tail(self, val):
        self.stack1.append(val)

    def delete_head(self):
        if not self.stack2:
            while self.stack1:
                val = self.stack1.pop()
                self.stack2.append(val)
        if not self.stack2:
            raise IndexError("empty queue")
        self.stack2.pop()


# test
if __name__ == "__main__":
    # stack => []
    q = Queue()
    q.append_tail(1)
    q.append_tail(2)
    q.append_tail(3)
    q.delete_head()
    q.append_tail(4)
    q.delete_head()
    q.delete_head()
    q.delete_head()

    q.delete_head()

旋轉(zhuǎn)數(shù)組的最小數(shù)

描述:旋轉(zhuǎn)數(shù)組([1,2,3,4,5,6,7] => [4,5,6,7, 1,2,3]) 把一個(gè)有序數(shù)組的部分最小值放到后面祥绞,我們的要做的就是根據(jù)這個(gè)旋轉(zhuǎn)數(shù)組找出最小值 1

思路1:從頭遍歷,復(fù)雜度為$O(n)$

思路2: 類似二分查找鸭限,根據(jù)題意旋轉(zhuǎn)數(shù)組的特性(最大值和最小值靠在一起的蜕径,就像這種走勢(shì) /\ ),定義兩個(gè)索引败京,讓這索引1不投涤鳎靠近最大值,索引2不蜕穆螅靠近最小值

def min_num(arr):
    first = 0
    end = len(arr) - 1

    while first != end - 1:
        mid = (end + first) / 2
        if arr[mid] > arr[first]:
            first = mid
        else:
            end = mid

    return arr[end]

# test
if __name__ == "__main__":
    print min_num([4, 5, 6, 7, 1, 2, 3])
    # ==> 1

斐波那契數(shù)

描述:略
思路1:就是遞歸了嘍朴皆,簡(jiǎn)單清晰,不過(guò)效率很低 $O(2^n)$,

def fib(num):
    if num == 0:
        return 0
    elif num == 1:
        return 1
    else:
        return fib(num - 1) + fib(num - 2)


# test
if __name__ == "__main__":
    print fib(0)
    print fib(1)
    print fib(2)
    print fib(3)
    print fib(10)
    print fib(100) # 下午吃飯回來(lái)還沒(méi)完泛粹,放棄了遂铡。。晶姊。

思路2: 用循環(huán)代替扒接, $O(n)$

def fib2(n):
    if n < 2:
        return n

    fib_n = 0

    fib_one = 0
    fib_two = 1
    for i in range(n):
        fib_n = fib_one + fib_two
        fib_one = fib_two
        fib_two = fib_n

    return fib_n


# test
if __name__ == "__main__":
    import time

    b = int(time.time() * 1000000)
    fib2(32)
    print int(time.time() * 1000000) - b
    #=> 77

二進(jìn)制中的1的個(gè)數(shù)

描述: 計(jì)算一個(gè)整數(shù)的二進(jìn)制中的1的個(gè)數(shù)

思路1: 判斷最右一位是不是,記錄们衙,右移一位钾怔;...

def count_one(n):
    count = 0
    while n:
        if n & 1:
            count += 1
        n >>= 1
    return count



# test
if __name__ == "__main__":
    print count_one(1)  # => 1
    print count_one(7346273462734697342374629346234)  # => 53

思路2: 上面的算法不能判斷負(fù)數(shù)的,因?yàn)樨?fù)數(shù)右移砍艾,左邊補(bǔ)的是1蒂教,所以陷入死循環(huán)

我們可以不右移n,而是向左移動(dòng)1(flag)

def count_one_2(n):
    count = 0

    flag = 1

    for i in xrange(64):  因?yàn)閜ython的整數(shù)沒(méi)有位數(shù)限制,我們自定義自己機(jī)器的位數(shù)
        if n & flag:
            count += 1
        flag <<= 1

    return count


# test
if __name__ == "__main__":
    print count_one_2(1)  #==>
    print count_one_2(-1)  #== 64
    print count_one_2(-10)  #==> 62

思路3: 主要是找到一個(gè)這樣的規(guī)律 n & (n-1) = 這個(gè)數(shù)的最右一位1變成變成0脆荷, 舉個(gè)例子:

1100 & (1100 - 1) = 1000; 看到了嗎凝垛,1100 => 1000懊悯,基于此的算法

def count_one_3(n):
    count = 0

    while n:
        count += 1
        n &= (n - 1)

    return count


# test
if __name__ == "__main__":
    print count_one_3(1)
    print count_one_3(10) 
    # print count_one_3(-1)
    # print count_one_3(-10)  # 只能判斷正數(shù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市梦皮,隨后出現(xiàn)的幾起案子炭分,更是在濱河造成了極大的恐慌,老刑警劉巖剑肯,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捧毛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡让网,警方通過(guò)查閱死者的電腦和手機(jī)呀忧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)溃睹,“玉大人而账,你說(shuō)我怎么就攤上這事∫蚱” “怎么了泞辐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)竞滓。 經(jīng)常有香客問(wèn)我咐吼,道長(zhǎng),這世上最難降的妖魔是什么商佑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任锯茄,我火速辦了婚禮,結(jié)果婚禮上茶没,老公的妹妹穿的比我還像新娘撇吞。我一直安慰自己,他們只是感情好礁叔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著迄薄,像睡著了一般琅关。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上讥蔽,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天涣易,我揣著相機(jī)與錄音,去河邊找鬼冶伞。 笑死新症,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的响禽。 我是一名探鬼主播徒爹,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼荚醒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了隆嗅?” 一聲冷哼從身側(cè)響起界阁,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胖喳,沒(méi)想到半個(gè)月后泡躯,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丽焊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年较剃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片技健。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡写穴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出凫乖,到底是詐尸還是另有隱情确垫,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布帽芽,位于F島的核電站删掀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏导街。R本人自食惡果不足惜披泪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望搬瑰。 院中可真熱鬧款票,春花似錦、人聲如沸泽论。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)翼悴。三九已至缚够,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鹦赎,已是汗流浹背谍椅。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留古话,地道東北人雏吭。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像陪踩,于是被迫代替她去往敵國(guó)和親杖们。 傳聞我的和親對(duì)象是個(gè)殘疾皇子悉抵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容