算法1

这里是我算法练习的一些例子,当作思维训练,题目来主要来自自剑指offer,我用python作为实现语言,个别可能没有测试完整的,欢迎通过简书交流

二维数组查找

描述:在二维数组中,每一行按照从左到右递增,每一列按照从上到下递增,输入一个这样的二维数组(1),和一个整数7,找到这个整数返回 True, 否则 False

1 2 8 9

2 4 9 12

4 7 10 13

思路1: 最原始的想法当然是遍历所有的元素,复杂度是 O(n^2)

思路2: 选取右上角的数字(其实左下角也可以),然后比较与数字7的大小,如果等于,查找过程结束;如果大于,就删除整个列;如果小于,就删除整个行, 复杂度O(n)$

简洁易懂,下面是我的python实现:

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)

从尾到头打印链表

链表实现:使用tuple表示一个Node

思路1: 遍历链表,存到栈里面,然后输出栈, 但其实我们不用手动实现栈,直接用递归函数就可以了

貌似过于简单了:)

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:上面的算法可以进行优化,递归函数在数据量大的时候会导致栈溢出, 可以用循环代替,或者尾递归优化(就是保证函数的最后一步是调用自身),但是python不支持尾递归优化,而且永远不会支持,java也是不支持的,尾递归优化貌似只在函数式语言中支持的比较好,但神奇的是es6在开启严格模式下是支持的

重建二叉树

描述:根据二叉树的前序遍历,中序遍历 重建整个二叉树

思路:还是递归,前序的第一个元素就是root, 根据root我们可以找到中序左子树, 中序右子树;然后找到前序左子树,前序右子树;递归找下去… 还是看代码吧

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)   # 递归构建左子树
    right = rebuild(preorder_right, inorder_right)  # 递归构建右子树
    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)

用两个栈实现队列

描述:用两个栈实现一个队列

思路:维护两个栈,栈1负责插入操作,栈2负责删除操作,当栈2为空时,将栈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()

旋转数组的最小数

描述:旋转数组([1,2,3,4,5,6,7] => [4,5,6,7, 1,2,3]) 把一个有序数组的部分最小值放到后面,我们的要做的就是根据这个旋转数组找出最小值 1

思路1:从头遍历,复杂度为$O(n)$

思路2: 类似二分查找,根据题意旋转数组的特性(最大值和最小值靠在一起的,就像这种走势 /\ ),定义两个索引,让这索引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

斐波那契数

描述:略
思路1:就是递归了喽,简单清晰,不过效率很低 $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) # 下午吃饭回来还没完,放弃了。。。

思路2: 用循环代替, $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

二进制中的1的个数

描述: 计算一个整数的二进制中的1的个数

思路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: 上面的算法不能判断负数的,因为负数右移,左边补的是1,所以陷入死循环

我们可以不右移n,而是向左移动1(flag)

def count_one_2(n):
    count = 0

    flag = 1

    for i in xrange(64):  因为python的整数没有位数限制,我们自定义自己机器的位数
        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: 主要是找到一个这样的规律 n & (n-1) = 这个数的最右一位1变成变成0, 举个例子:

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)  # 只能判断正数
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • 1 序 2016年6月25日夜,帝都,天下着大雨,拖着行李箱和同学在校门口照了最后一张合照,搬离寝室打车去了提前租...
    RichardJieChen阅读 5,085评论 0 12
  • 1、 对以下一组数据进行降序排序(冒泡排序)。“24,80,35,8,9,54,76,45,5,63” int ...
    面条168阅读 667评论 0 3
  • 1.把二元查找树转变成排序的双向链表 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不...
    曲终人散Li阅读 3,304评论 0 19
  • 第一章 绪论 什么是数据结构? 数据结构的定义:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。 第二章...
    SeanCheney阅读 5,760评论 0 19
  • 树的概述 树是一种非常常用的数据结构,树与前面介绍的线性表,栈,队列等线性结构不同,树是一种非线性结构 1.树的定...
    Jack921阅读 4,445评论 1 31