├── README.md ├── fifth ├── README.md ├── second │ ├── README.md │ ├── thirty.py │ ├── thirty_one.py │ ├── thirty_three.py │ ├── thirty_two.py │ └── twenty_nine.py └── third │ ├── README.md │ ├── thirty_five.py │ ├── thirty_four.py │ ├── thirty_seven.py │ └── thirty_six.py ├── fourth ├── README.md ├── fourth │ ├── README.md │ ├── twenty_eight.py │ ├── twenty_seven.py │ └── twenty_six.py ├── second │ ├── README.md │ ├── nineteen.py │ └── twenty.py └── third │ ├── README.md │ ├── twenty_five.py │ ├── twenty_four.py │ ├── twenty_one.py │ ├── twenty_three.py │ └── twenty_two.py ├── second ├── README.md ├── fourth │ ├── README.md │ ├── eight.py │ ├── nine.py │ └── ten.py ├── second │ ├── README.md │ ├── test_module.py │ ├── use_decorator.py │ ├── use_module.py │ └── use_new.py └── third │ ├── README.md │ ├── five.py │ ├── seven.py │ ├── six.py │ └── three.py ├── seventh ├── README.md ├── first │ ├── README.md │ └── fourty_nine.py └── second │ ├── README.md │ └── fifty.py ├── sixth ├── README.md ├── fifth │ ├── README.md │ ├── fourty_seven.py │ └── fourty_six.py ├── fourth │ ├── README.md │ ├── fourty_five.py │ ├── fourty_four.py │ └── fourty_three.py └── third │ ├── README.md │ ├── fourty.py │ ├── fourty_one_a.py │ ├── fourty_one_b.py │ ├── fourty_two_a.py │ ├── fourty_two_b.py │ ├── thirty_eight.py │ └── thirty_nine.py └── third ├── README.md ├── fourth ├── README.md ├── eighteen.py ├── fifteen.py ├── seventeen.py └── sixteen.py └── third ├── README.md ├── eleven.py ├── fourteen.py ├── thirteen.py └── twelve.py /README.md: -------------------------------------------------------------------------------- 1 | # 《剑指Offer》面试题: Python实现 2 | 3 | ## 第2章 [面试基础知识](/second) 4 | ### 2.2 [编程语言](/second/second) 5 | > #### 面试题2 [使用Python实现单例模式](./second#面试题2-使用Python实现单例模式) 6 | ### 2.3 [数据结构](/second/third) 7 | > #### 面试题3 [二维数组中的查找](./second/third#面试题3-二维数组中的查找) 8 | > #### 面试题4 [替换空格](/second/third#面试题4-替换空格) 9 | > #### 面试题5 [从尾到头打印单链表](/second/third#面试题5-从尾到头打印单链表) 10 | > #### 面试题6 [重建二叉树](/second/third#面试题6-重建二叉树) 11 | > #### 面试题7 [用两个栈实现队列](/second/third#面试题7-用两个栈实现队列) 12 | ### 2.4 [算法和数据操作](/second/fourth) 13 | > #### 面试题8 [旋转数组的最小数字](./second/fourth#面试题8-旋转数组的最小数字) 14 | > #### 面试题9 [斐波那契数列](./second/fourth#面试题9-斐波那契数列) 15 | > #### 面试题10 [二进制中1的个数](./second/fourth#面试题10-二进制中1的个数) 16 | 17 | ## 第3章 [高质量代码](/third) 18 | ### 3.3 [代码的完整性](/third/third) 19 | > #### 面试题11 [数值的整数次方](./third/third#面试题11-数值的整数次方) 20 | > #### 面试题12 [打印1到最大的n位数](./third/third#面试题12-打印1到最大的n位数) 21 | > #### 面试题13 [O(1)时间删除链表结点](./third/third#面试题13-o1时间删除链表结点) 22 | > #### 面试题14 [调整数组顺序使寄数位于偶数前面](./third/third#面试题14-调整数组顺序使奇数位于偶数前面) 23 | ### 3.4 [代码的鲁棒性](/third/fourth) 24 | > #### 面试题15 [链表中倒数第k个结点](./third/fourth#面试题15-链表中倒数第k个结点) 25 | > #### 面试题16 [反转链表](./third/fourth#面试题16-反转链表) 26 | > #### 面试题17 [合并两个排序的链表](./third/fourth#面试题17-合并两个排序的链表) 27 | > #### 面试题18 [树的子结构](./third/third#面试题18-树的子结构) 28 | 29 | ## 第4章 [解决面试题思路](/fourth) 30 | ### 4.2 [画图让抽象问题形象化](./fourth/second) 31 | > #### 面试题19 [二叉树的镜像](./fourth/second#面试题19-二叉树的镜像) 32 | > #### 面试题20 [顺时针打印矩阵](./fourth/second#面试题20-顺时针打印矩阵) 33 | ### 4.3 [举例让抽象问题具体化](./fourth/third) 34 | > #### 面试题21 [包含min函数的栈](./fourth/third#面试题21-包含min函数的栈) 35 | > #### 面试题22 [栈的压入弹出序列](./fourth/third#面试题22-栈的压入弹出序列) 36 | > #### 面试题23 [从上往下打印二叉树](./fourth/third#面试题23-从上往下打印二叉树) 37 | > #### 面试题24 [二叉树的后序遍历序列](./fourth/third#面试题24-二叉搜索树的后序遍历序列) 38 | > #### 面试题25 [二叉树中和为某一值的路径](./fourth/third#面试题25-二叉树中和为某一值的路径) 39 | ### 4.4 [分解让复杂问题简单化](./fourth/fourth) 40 | > #### 面试题26 [复杂链表的复制](./fourth/fourth#面试题26-复杂链表的复制) 41 | > #### 面试题27 [二叉搜索树与双向链表](./fourth/fourth#面试题27-二叉搜索树与双向链表) 42 | > #### 面试题28 [字符串的排列](./fourth/fourth#面试题28-字符串的排列) 43 | 44 | ## 第5章 [优化时间和空间效率](./fifth) 45 | ### 5.2 [时间效率](./fifth/second) 46 | > #### 面试题29 [数组中出现次数超过一半的数字](./fifth/second#面试题29-数组中出现次数超过一半的数字) 47 | > #### 面试题30 [最小的k个数](./fifth/second#面试题30-最小的k个数) 48 | > #### 面试题31 [连续子数组的最大和](./fifth/second#面试题31-连续子数组的最大和) 49 | > #### 面试题32 [从1到n整数中1出现的次数](./fifth/second#面试题32-从1到n整数中1出现的次数) 50 | > #### 面试题33 [把数组排成最小的数](./fifth/second#面试题33-把数组排成最小的数) 51 | ### 5.3 [时间效率与空间效率的平衡](./fifth/third) 52 | > #### 面试题34 [丑数](./fifth/third#面试题34-丑数) 53 | > #### 面试题35 [第一个只出现一次的字符](./fifth/third#面试题35-第一个只出现一次的字符) 54 | > #### 面试题36 [数组中的逆序对](./fifth/third#面试题36-数组中的逆序对) 55 | > #### 面试题37 [两个链表的第一个公共结点](./fifth/third#面试题37-两个链表的第一个公共结点) 56 | 57 | ## 第6章 [面试能力](/sixth) 58 | ### 6.3 [知识迁移能力](./sixth/third) 59 | > #### 面试题38 [数字在排序数组中出现的次数](./sixth/third#面试题38-数字在排序数组中出现的次数) 60 | > #### 面试题39 [二叉树的深度](./sixth/third#面试题39-二叉树的深度) 61 | > #### 面试题40 [数组中只出现一次的数字](./sixth/third#面试题40-数组中只出现一次的数字) 62 | > #### 面试题41 [和为s的两个数字VS和为s的连续正数序列](./sixth/third#面试题41-和为s的两个数字vs和为s的连续正数序列) 63 | > #### 面试题42 [翻转单词顺序与左旋转字符串](./sixth/third#面试题42-翻转单词顺序与左旋转字符串) 64 | ### 6.4 [抽象建模能力](./sixth/fourth) 65 | > #### 面试题43 [n个骰子的点数](./sixth/fourth#面试题43-n个骰子的点数) 66 | > #### 面试题44 [扑克牌的顺子](./sixth/fourth#面试题44-扑克牌的顺子) 67 | > #### 面试题45 [圆圈中最后剩下的数字](./sixth/fourth#面试题45-圆圈中最后剩下的数字) 68 | ### 6.5 [发散思维能力](./sixth/fifth) 69 | > #### 面试题46 [求1+2...+n](./sixth/fifth#面试题46-求1+2...+n) 70 | > #### 面试题47 [不用加减乘除做加法](./sixth/fifth#面试题47-不用加减乘除做加法) 71 | > #### 面试题48 [不能被继承的类](./sixth/fifth#面试题48-不能被继承的类) 72 | 73 | ## 第7章 [面试案例](./seventh) 74 | ### 7.1 [案例一](./seventh/first) 75 | > #### 面试题49 [把字符串转化成整数](./seventh/first#面试题49-把字符串转化成整数) 76 | ### 7.2 [案例二](./seventh/second) 77 | > #### 面试题50 [树中两个结点的最低公共祖先](./seventh/second#面试题50-树中两个结点的最低公共祖先) 78 | 79 | -------------------------------------------------------------------------------- /fifth/README.md: -------------------------------------------------------------------------------- 1 | # 第5章 优化时间和空间效率 2 | 3 | ## 5.2 [时间效率](./second) 4 | > #### 面试题29 [数组中出现次数超过一半的数字](./second#面试题29-数组中出现次数超过一半的数字) 5 | > #### 面试题30 [最小的k个数](./second#面试题30-最小的k个数) 6 | > #### 面试题31 [连续子数组的最大和](./second#面试题31-连续子数组的最大和) 7 | > #### 面试题32 [从1到n整数中1出现的次数](./second#面试题32-从1到n整数中1出现的次数) 8 | > #### 面试题33 [把数组排成最小的数](./second#面试题33-把数组排成最小的数) 9 | 10 | ## 5.3 [时间效率与空间效率的平衡](./third) 11 | > #### 面试题34 [丑数](./third#面试题34-丑数) 12 | > #### 面试题35 [第一个只出现一次的字符](./third#面试题35-第一个只出现一次的字符) 13 | > #### 面试题36 [数组中的逆序对](./third#面试题36-数组中的逆序对) 14 | > #### 面试题37 [两个链表的第一个公共结点](./third#面试题37-两个链表的第一个公共结点) 15 | 16 | -------------------------------------------------------------------------------- /fifth/second/README.md: -------------------------------------------------------------------------------- 1 | # 5.2 时间效率 2 | 3 | ## 面试题29 数组中出现次数超过一半的数字 4 | > 思路: 使用hash,key是数字,value是出现的次数 5 | > 6 | > 注意: 列表的len方法的时间复杂度是O(1) 7 | > 8 | 9 | ```python 10 | def get_more_half_num(nums): 11 | hashes = dict() 12 | length = len(nums) 13 | for n in nums: 14 | hashes[n] = hashes[n] + 1 if hashes.get(n) else 1 15 | if hashes[n] > length / 2: 16 | return n 17 | ``` 18 | 19 | ## 面试题30 最小的k个数 20 | > 要求:求数组中出现次数超过一半的数字 21 | > 22 | > 思路: 使用heapq,该模块是一个最小堆,需要转化成最大堆,只要在入堆的时候把值取反就可以转化成最大堆(仅适用于数字) 23 | > 24 | > 思路二: 数组比较小的时候可以直接使用heapq的nsmallest方法 25 | 26 | ```python 27 | import heapq 28 | 29 | 30 | def get_least_k_nums(nums, k): 31 | # 数组比较小的时候可以直接使用 32 | return heapq.nsmallest(k, nums) 33 | 34 | 35 | class MaxHeap(object): 36 | def __init__(self, k): 37 | self.k = k 38 | self.data = [] 39 | 40 | def push(self, elem): 41 | elem = -elem # 入堆的时候取反,堆顶就是最大值的相反数了 42 | if len(self.data) < self.k: 43 | heapq.heappush(self.data, elem) 44 | else: 45 | least = self.data[0] 46 | if elem > least: 47 | heapq.heapreplace(self.data, elem) 48 | 49 | def get_least_k_nums(self): 50 | return sorted([-x for x in self.data]) 51 | ``` 52 | 53 | ## 面试题31 连续子数组的最大和 54 | > 思路: 动态规划问题 55 | 56 | ```python 57 | def max_sum(nums): 58 | ret = float("-inf") # 负无穷 59 | if not nums: 60 | return ret 61 | current = 0 62 | for i in nums: 63 | if current <= 0: 64 | current = i 65 | else: 66 | current += i 67 | ret = max(ret, current) 68 | return ret 69 | ``` 70 | 71 | ## 面试题32 从1到n整数中1出现的次数 72 | > 要求:求从1到n整数的十进制表示中,1出现的次数 73 | > 74 | > 思路: 获取每个位数区间上所有数中包含1的个数,然后分别对高位分析,然后递归的处理低位数 75 | > 76 | > 此题中,作者的描述我没有理解,按照自己的理解写了一下,具体内容请点击[这里](http://www.cnblogs.com/qiaojushuang/p/7780445.html) 77 | 78 | ```python 79 | def get_digits(n): 80 | # 求整数n的位数 81 | ret = 0 82 | while n: 83 | ret += 1 84 | n /= 10 85 | return ret 86 | 87 | 88 | def get_1_digits(n): 89 | """ 90 | 获取每个位数之间1的总数 91 | :param n: 位数 92 | """ 93 | if n <= 0: 94 | return 0 95 | if n == 1: 96 | return 1 97 | current = 9 * get_1_digits(n-1) + 10 ** (n-1) 98 | return get_1_digits(n-1) + current 99 | 100 | 101 | def get_1_nums(n): 102 | if n < 10: 103 | return 1 if n >= 1 else 0 104 | digit = get_digits(n) # 位数 105 | low_nums = get_1_digits(digit-1) # 最高位之前的1的个数 106 | high = int(str(n)[0]) # 最高位 107 | low = n - high * 10 ** (digit-1) # 低位 108 | 109 | if high == 1: 110 | high_nums = low + 1 # 最高位上1的个数 111 | all_nums = high_nums 112 | else: 113 | high_nums = 10 ** (digit - 1) 114 | all_nums = high_nums + low_nums * (high - 1) # 最高位大于1的话,统计每个多位数后面包含的1 115 | return low_nums + all_nums + get_1_nums(low) 116 | ``` 117 | 118 | ## 面试题33 把数组排成最小的数 119 | > 要求:把数组中的值拼接,找出能产生的最小的数[321,32,3]最小的数是321323 120 | > 121 | > 思路: Python中不需要考虑大整数,需要自己定义一个数组排序规则,直接调用库函数就可以 122 | 123 | ```python 124 | def cmp(a, b): 125 | return int(str(a)+str(b)) - int(str(b)+str(a)) 126 | 127 | 128 | def print_mini(nums): 129 | print int(''.join([str(num) for num in sorted(nums, cmp=cmp)])) 130 | ``` -------------------------------------------------------------------------------- /fifth/second/thirty.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求数组中最小的k个数 4 | 思路:使用heapq,该模块是一个最小堆,需要转化成最大堆, 5 | 只要在入堆的时候把值取反就可以转化成最大堆,仅适用于数字 6 | """ 7 | import random 8 | import heapq 9 | 10 | 11 | def get_least_k_nums(nums, k): 12 | # 数组比较小的时候可以直接使用 13 | return heapq.nsmallest(k, nums) 14 | 15 | 16 | class MaxHeap(object): 17 | def __init__(self, k): 18 | self.k = k 19 | self.data = [] 20 | 21 | def push(self, elem): 22 | elem = -elem # 入堆的时候取反,堆顶就是最大值的相反数了 23 | if len(self.data) < self.k: 24 | heapq.heappush(self.data, elem) 25 | else: 26 | least = self.data[0] 27 | if elem > least: 28 | heapq.heapreplace(self.data, elem) 29 | 30 | def get_least_k_nums(self): 31 | return sorted([-x for x in self.data]) 32 | 33 | if __name__ == '__main__': 34 | test = random.sample(xrange(100000), 100) 35 | print get_least_k_nums(test, 4) 36 | h = MaxHeap(4) 37 | for t in test: 38 | h.push(t) 39 | print h.get_least_k_nums() 40 | -------------------------------------------------------------------------------- /fifth/second/thirty_one.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 连续子数组的最大和 4 | 动态规划问题 5 | """ 6 | 7 | 8 | def max_sum(nums): 9 | ret = float("-inf") # 负无穷 10 | if not nums: 11 | return ret 12 | current = 0 13 | for i in nums: 14 | if current <= 0: 15 | current = i 16 | else: 17 | current += i 18 | ret = max(ret, current) 19 | return ret 20 | 21 | if __name__ == '__main__': 22 | test = [1, 2, -2, 3, 6, 0, -2] 23 | print max_sum(test) 24 | -------------------------------------------------------------------------------- /fifth/second/thirty_three.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 把数组中的值拼接,找出能产生的最小的数[321,32,3]最小的数是321323 4 | Python中不需要考虑大整数,需要自己定义一个数组排序规则,直接调用库函数就可以 5 | """ 6 | 7 | 8 | def cmp(a, b): 9 | return int(str(a)+str(b)) - int(str(b)+str(a)) 10 | 11 | 12 | def print_mini(nums): 13 | if not nums: 14 | return 15 | print int(''.join([str(num) for num in sorted(nums, cmp=cmp)])) 16 | 17 | 18 | if __name__ == '__main__': 19 | test = [] 20 | print_mini(test) 21 | -------------------------------------------------------------------------------- /fifth/second/thirty_two.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求从1到n整数的十进制表示中,1出现的次数 4 | 思路:获取每个位数区间上所有数中包含1的个数,然后分别对高位分析,然后递归的处理低位数 5 | """ 6 | 7 | 8 | def get_digits(n): 9 | # 求整数n的位数 10 | ret = 0 11 | while n: 12 | ret += 1 13 | n /= 10 14 | return ret 15 | 16 | 17 | def get_1_digits(n): 18 | """ 19 | 获取每个位数之间1的总数 20 | :param n: 位数 21 | """ 22 | if n <= 0: 23 | return 0 24 | if n == 1: 25 | return 1 26 | current = 9 * get_1_digits(n-1) + 10 ** (n-1) 27 | return get_1_digits(n-1) + current 28 | 29 | 30 | def get_1_nums(n): 31 | if n < 10: 32 | return 1 if n >= 1 else 0 33 | digit = get_digits(n) # 位数 34 | low_nums = get_1_digits(digit-1) # 最高位之前的1的个数 35 | high = int(str(n)[0]) # 最高位 36 | low = n - high * 10 ** (digit-1) # 低位 37 | 38 | if high == 1: 39 | high_nums = low + 1 # 最高位上1的个数 40 | all_nums = high_nums 41 | else: 42 | high_nums = 10 ** (digit - 1) 43 | all_nums = high_nums + low_nums * (high - 1) # 最高位大于1的话,统计每个多位数后面包含的1 44 | return low_nums + all_nums + get_1_nums(low) 45 | 46 | 47 | def test_n(num): 48 | # 常规方法用来比较 49 | ret = 0 50 | for n in range(1, num+1): 51 | for s in str(n): 52 | if s == '1': 53 | ret += 1 54 | return ret 55 | 56 | if __name__ == '__main__': 57 | test = 9923446 58 | import time 59 | t = time.clock() 60 | print test_n(test) 61 | print time.clock() - t 62 | t1 = time.clock() 63 | print get_1_nums(test) 64 | print time.clock() - t1 65 | -------------------------------------------------------------------------------- /fifth/second/twenty_nine.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 数组中出现次数超过一半的数字 4 | 思路: 使用hash,key是数字,value是出现的次数 5 | 注意: 列表的len方法的时间复杂度是O(1) 6 | """ 7 | 8 | 9 | def get_more_half_num(nums): 10 | hashes = dict() 11 | length = len(nums) 12 | for n in nums: 13 | hashes[n] = hashes[n] + 1 if hashes.get(n) else 1 14 | if hashes[n] > length / 2: 15 | return n 16 | 17 | if __name__ == '__main__': 18 | test = [1, 2, 1, 2, 3, 1, 1] 19 | print get_more_half_num(test) 20 | -------------------------------------------------------------------------------- /fifth/third/README.md: -------------------------------------------------------------------------------- 1 | # 5.3 时间效率与空间效率的平衡 2 | 3 | ## 面试题34 丑数 [LeetCode](https://leetcode.com/problems/ugly-number-ii/) 4 | > 要求:只含有2、3、5因子的数是丑数,求第1500个丑数 5 | > 6 | > 思路: 按顺序保存已知的丑数,下一个是已知丑数中某三个数乘以2,3,5中的最小值 7 | 8 | ```python 9 | class Solution(object): 10 | def nthUglyNumber(self, n): 11 | """ 12 | :type n: int 13 | :rtype: int 14 | """ 15 | ugly = [1] 16 | t2 = t3 = t5 = 0 17 | while len(ugly) < n: 18 | while ugly[t2] * 2 <= ugly[-1]: 19 | t2 += 1 20 | while ugly[t3] * 3 <= ugly[-1]: 21 | t3 += 1 22 | while ugly[t5] * 5 <= ugly[-1]: 23 | t5 += 1 24 | ugly.append(min(ugly[t2]*2, ugly[t3]*3, ugly[t5]*5)) 25 | return ugly[-1] 26 | ``` 27 | 28 | ## 面试题35 第一个只出现一次的字符 29 | > 要求:求字符串中第一个只出现一次的字符 30 | > 31 | > 思路: 使用两个hash,一个记录每个字符穿线的次数,另一个记录每个字符第一次出现的位置 32 | 33 | ```python 34 | def first_not_repeating_char(string): 35 | if not string: 36 | return -1 37 | count = {} 38 | loc = {} 39 | for k, s in enumerate(string): 40 | count[s] = count[s] + 1 if count.get(s) else 1 41 | loc[s] = loc[s] if loc.get(s) else k 42 | ret = float('inf') 43 | for k in loc.keys(): 44 | if count.get(k) == 1 and loc[k] < ret: 45 | ret = loc[k] 46 | return ret 47 | ``` 48 | 49 | ## 面试题36 数组中的逆序对 50 | > 要求:在一个数组中,前面的数字比后面的大,就是一个逆序对,求总数 51 | > 52 | > 思路: 归并排序,先把数组依次拆开,然后合并的时候统计逆序对数目,并排序 53 | 54 | ```python 55 | import copy 56 | 57 | 58 | def get_inverse_pairs(nums): 59 | if not nums: 60 | return 0 61 | start, end = 0, len(nums) - 1 62 | tmp = copy.deepcopy(nums) 63 | return inverse_pairs(tmp, start, end) 64 | 65 | 66 | def inverse_pairs(tmp, start, end): 67 | if start == end: # 递归结束条件 68 | return 0 69 | mid = (end - start) / 2 # 分别对左右两边递归求值 70 | left = inverse_pairs(tmp, start, start+mid) 71 | right = inverse_pairs(tmp, start+mid+1, end) 72 | 73 | count = 0 # 本次逆序对数目 74 | l_right, r_right = start + mid, end 75 | t = [] 76 | while l_right >= start and r_right >= start + mid + 1: 77 | if tmp[l_right] > tmp[r_right]: 78 | t.append(tmp[l_right]) 79 | count += (r_right - mid - start) 80 | l_right -= 1 81 | else: 82 | t.append(tmp[r_right]) 83 | r_right -= 1 84 | while l_right >= start: 85 | t.append(tmp[l_right]) 86 | l_right -= 1 87 | while r_right >= start+mid+1: 88 | t.append(tmp[r_right]) 89 | r_right -= 1 90 | tmp[start:end+1] = t[::-1] 91 | return count + left + right 92 | ``` 93 | 94 | ## 面试题37 两个链表的第一个公共结点 95 | > 思路: 先获取到两个链表的长度,然后长的链表先走多的几步,之后一起遍历 96 | > 97 | > 文件thirty_seven.py中包含了设置链表公共结点的代码,可以用来测试 98 | 99 | ```python 100 | def get_first_common_node(link1, link2): 101 | if not link1 or not link2: 102 | return None 103 | length1 = length2 = 0 104 | move1, move2 = link1, link2 105 | while move1: # 获取链表长度 106 | length1 += 1 107 | move1 = move1.next 108 | while move2: 109 | length2 += 1 110 | move2 = move2.next 111 | while length1 > length2: # 长链表先走多的长度 112 | length1 -= 1 113 | link1 = link1.next 114 | while length2 > length1: 115 | length2 -= 1 116 | link2 = link2.next 117 | while link1: # 链表一起走 118 | if link1 == link2: 119 | return link1 120 | link1, link2 = link1.next, link2.next 121 | return None 122 | ``` -------------------------------------------------------------------------------- /fifth/third/thirty_five.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求字符串中第一个只出现一次的字符 4 | 使用两个hash,一个记录每个字符穿线的次数,另一个记录每个字符第一次出现的位置 5 | """ 6 | 7 | 8 | def first_not_repeating_char(string): 9 | if not string: 10 | return -1 11 | count = {} 12 | loc = {} 13 | for k, s in enumerate(string): 14 | count[s] = count[s] + 1 if count.get(s) else 1 15 | loc[s] = loc[s] if loc.get(s) else k 16 | ret = float('inf') 17 | for k in loc.keys(): 18 | if count.get(k) == 1 and loc[k] < ret: 19 | ret = loc[k] 20 | return ret 21 | 22 | if __name__ == '__main__': 23 | test = 'abaccbdse' 24 | print first_not_repeating_char(test) 25 | -------------------------------------------------------------------------------- /fifth/third/thirty_four.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 只含有2、3、5因子的数是丑数,求第1500个丑数 4 | 按顺序保存已知的丑数,下一个是已知丑数中某三个数乘以2,3,5中的最小值 5 | """ 6 | 7 | 8 | class Solution(object): 9 | def nthUglyNumber(self, n): 10 | """ 11 | :type n: int 12 | :rtype: int 13 | """ 14 | ugly = [1] 15 | t2 = t3 = t5 = 0 16 | while len(ugly) < n: 17 | while ugly[t2] * 2 <= ugly[-1]: 18 | t2 += 1 19 | while ugly[t3] * 3 <= ugly[-1]: 20 | t3 += 1 21 | while ugly[t5] * 5 <= ugly[-1]: 22 | t5 += 1 23 | ugly.append(min(ugly[t2]*2, ugly[t3]*3, ugly[t5]*5)) 24 | return ugly[-1] 25 | 26 | 27 | if __name__ == '__main__': 28 | print Solution().nthUglyNumber(1500) 29 | -------------------------------------------------------------------------------- /fifth/third/thirty_seven.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求两个链表的第一个公共结点 4 | 先获取到两个链表的长度,然后长的链表先走多的几步,之后一起遍历 5 | """ 6 | 7 | 8 | def get_first_common_node(link1, link2): 9 | if not link1 or not link2: 10 | return None 11 | length1 = length2 = 0 12 | move1, move2 = link1, link2 13 | while move1: # 获取链表长度 14 | length1 += 1 15 | move1 = move1.next 16 | while move2: 17 | length2 += 1 18 | move2 = move2.next 19 | while length1 > length2: # 长链表先走多的长度 20 | length1 -= 1 21 | link1 = link1.next 22 | while length2 > length1: 23 | length2 -= 1 24 | link2 = link2.next 25 | while link1: # 链表一起走 26 | if link1 == link2: 27 | return link1 28 | link1, link2 = link1.next, link2.next 29 | return None 30 | 31 | 32 | class ListNode(object): 33 | def __init__(self, x): 34 | self.val = x 35 | self.next = None 36 | 37 | 38 | class Nodes(object): 39 | def __init__(self, values=None): 40 | self.nodes = self._set_link(values) if values else None 41 | 42 | def get_link(self): 43 | return self.nodes 44 | 45 | def get_tail(self): 46 | # 获取尾指针 47 | tail = self.nodes 48 | while tail.next: 49 | tail = tail.next 50 | return tail 51 | 52 | def print_self(self): 53 | Nodes.print_link(self.nodes) 54 | 55 | @staticmethod 56 | def print_link(link=None): 57 | count = 1 58 | while link: 59 | if count == 1: 60 | print link.val, 61 | elif count % 5 == 0: 62 | print '->', link.val 63 | else: 64 | print '->', link.val, 65 | count += 1 66 | link = link.next 67 | print 68 | 69 | def _set_link(self, values): 70 | head = ListNode(0) 71 | move = head 72 | try: 73 | for val in values: 74 | tmp = ListNode(val) 75 | move.next = tmp 76 | move = move.next 77 | except Exception as e: 78 | print e 79 | return head.next 80 | 81 | if __name__ == '__main__': 82 | t1 = [1, 2, 3, 4] 83 | t2 = [5, 6, 7, 8, 12] 84 | t3 = [9, 10, 11] 85 | node1, node2, common = Nodes(t1), Nodes(t2), Nodes(t3) 86 | h1 = node1.get_link() 87 | h2 = node2.get_link() 88 | h3 = common.get_link() 89 | tail1 = node1.get_tail() 90 | tail2 = node2.get_tail() 91 | tail2.next = h3 # 设置公共链表 92 | tail1.next = h3 93 | print get_first_common_node(h1, h2) 94 | print h3 95 | -------------------------------------------------------------------------------- /fifth/third/thirty_six.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 在一个数组中,前面的数字比后面的大,就是一个逆序对,求总数 4 | 归并排序,先把数组依次拆开,然后合并的时候统计逆序对数目,并排序 5 | """ 6 | import copy 7 | 8 | 9 | def get_inverse_pairs(nums): 10 | if not nums: 11 | return 0 12 | start, end = 0, len(nums) - 1 13 | tmp = copy.deepcopy(nums) 14 | return inverse_pairs(tmp, start, end) 15 | 16 | 17 | def inverse_pairs(tmp, start, end): 18 | if start == end: # 递归结束条件 19 | return 0 20 | mid = (end - start) / 2 # 分别对左右两边递归求值 21 | left = inverse_pairs(tmp, start, start+mid) 22 | right = inverse_pairs(tmp, start+mid+1, end) 23 | 24 | count = 0 # 本次逆序对数目 25 | l_right, r_right = start + mid, end 26 | t = [] 27 | while l_right >= start and r_right >= start + mid + 1: 28 | if tmp[l_right] > tmp[r_right]: 29 | t.append(tmp[l_right]) 30 | count += (r_right - mid - start) 31 | l_right -= 1 32 | else: 33 | t.append(tmp[r_right]) 34 | r_right -= 1 35 | while l_right >= start: 36 | t.append(tmp[l_right]) 37 | l_right -= 1 38 | while r_right >= start+mid+1: 39 | t.append(tmp[r_right]) 40 | r_right -= 1 41 | tmp[start:end+1] = t[::-1] 42 | return count + left + right 43 | 44 | if __name__ == '__main__': 45 | test = [7, 5, 6, 4, 8, 1, 2, 9] 46 | print get_inverse_pairs(test) 47 | -------------------------------------------------------------------------------- /fourth/README.md: -------------------------------------------------------------------------------- 1 | # 第4章 解决面试题的思路 2 | 3 | ## 4.2 [画图让抽象问题形象化](./second) 4 | > #### 面试题19 [二叉树的镜像](./second#面试题19-二叉树的镜像) 5 | > #### 面试题20 [顺时针打印矩阵](./second#面试题20-顺时针打印矩阵) 6 | 7 | ## 4.3 [举例让抽象问题具体化](./third) 8 | > #### 面试题21 [包含min函数的栈](./third#面试题21-包含min函数的栈) 9 | > #### 面试题22 [栈的压入弹出序列](./third#面试题22-栈的压入弹出序列) 10 | > #### 面试题23 [从上往下打印二叉树](./third#面试题23-从上往下打印二叉树) 11 | > #### 面试题24 [二叉树的后序遍历序列](./third#面试题24-二叉搜索树的后序遍历序列) 12 | > #### 面试题25 [二叉树中和为某一值的路径](./third#面试题25-二叉树中和为某一值的路径) 13 | 14 | ## 4.4 [分解让复杂问题简单化](./fourth) 15 | > #### 面试题26 [复杂链表的复制](./fourth#面试题26-复杂链表的复制) 16 | > #### 面试题27 [二叉搜索树与双向链表](./fourth#面试题27-二叉搜索树与双向链表) 17 | > #### 面试题28 [字符串的排列](./fourth#面试题28-字符串的排列) 18 | -------------------------------------------------------------------------------- /fourth/fourth/README.md: -------------------------------------------------------------------------------- 1 | # 4.4 分解让复杂问题简单化 2 | 3 | ## 面试题26 复杂链表的复制 4 | > 要求:链表中除了指向后一个结点的指针之外,还有一个指针指向任意结点 5 | > 6 | > 分为三步完成: 7 | > 8 | > 一:复制每个结点,并把新结点放在老结点后面,如1->2,复制为1->1->2->2 9 | > 10 | > 二:为每个新结点设置other指针 11 | > 12 | > 三:把复制后的结点链表拆开 13 | > 14 | > 题目设置了复杂链表的实现,测试代码见文件twenth_six.py 15 | > 16 | ```python 17 | class Solution(object): 18 | 19 | @staticmethod 20 | def clone_nodes(head): 21 | # 结点复制 22 | move = head 23 | while move: 24 | tmp = Node(move.val) 25 | tmp.next = move.next 26 | move.next = tmp 27 | move = tmp.next 28 | return head 29 | 30 | @staticmethod 31 | def set_nodes(head): 32 | # other指针设置 33 | move = head 34 | while move: 35 | m_next = move.next 36 | if move.other: 37 | m_next.other = move.other.next 38 | move = m_next.next 39 | return head 40 | 41 | @staticmethod 42 | def reconstruct_nodes(head): 43 | # 结点拆分 44 | ret = head.next if head else Node 45 | move = ret 46 | while head: 47 | head = move.next 48 | if head: 49 | move.next = head.next 50 | move = move.next 51 | return ret 52 | 53 | @staticmethod 54 | def clone_link(head): 55 | # 结果 56 | h = Solution.clone_nodes(head) 57 | h = Solution.set_nodes(h) 58 | ret = Solution.reconstruct_nodes(h) 59 | return ret 60 | ``` 61 | 62 | ## 面试题27 二叉搜索树与双向链表 63 | > 要求: 将二叉搜索树转化成一个排序的双向链表,只调整树中结点的指向 64 | > 65 | > 思路: 中序遍历,根结点的left指向左子树的最后一个(最大)值,right指向右子树的(最小)值 66 | > 67 | > 注意: 题目构造了一个普通二叉树用来测试,构造时按照二叉搜索树的顺序输入结点,空结点用None表示,详情见twenty_seven.py 68 | > 69 | 70 | ```python 71 | class Solution(object): 72 | 73 | @staticmethod 74 | def convert(tree): 75 | """结点转换""" 76 | if not tree: 77 | return None 78 | p_last = Solution.convert_nodes(tree, None) 79 | while p_last and p_last.left: # 获取链表头结点 80 | p_last = p_last.left 81 | return p_last 82 | 83 | @staticmethod 84 | def convert_nodes(tree, last): 85 | if not tree: 86 | return None 87 | if tree.left: 88 | last = Solution.convert_nodes(tree.left, last) 89 | if last: 90 | last.right = tree 91 | tree.left = last 92 | last = tree 93 | if tree.right: 94 | last = Solution.convert_nodes(tree.right, last) 95 | return last 96 | ``` 97 | 98 | ## 面试题28 字符串的排列 99 | > 要求:求输入字符串的全排列 100 | > 101 | > 思路:递归完成,也可以直接使用库函数 102 | > 103 | 104 | ```python 105 | def my_permutation(s): 106 | str_set = [] 107 | ret = [] # 最后的结果 108 | 109 | def permutation(string): 110 | for i in string: 111 | str_tem = string.replace(i, '') 112 | str_set.append(i) 113 | if len(str_tem) > 0: 114 | permutation(str_tem) 115 | else: 116 | ret.append(''.join(str_set)) 117 | str_set.pop() 118 | 119 | permutation(s) 120 | return ret 121 | ``` -------------------------------------------------------------------------------- /fourth/fourth/twenty_eight.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求输入字符串的全排列 4 | 递归完成,也可以直接使用库函数 5 | """ 6 | 7 | from itertools import permutations 8 | 9 | 10 | def my_permutation(s): 11 | str_set = [] 12 | ret = [] # 最后的结果 13 | 14 | def permutation(string): 15 | for i in string: 16 | str_tem = string.replace(i, '') 17 | str_set.append(i) 18 | if len(str_tem) > 0: 19 | permutation(str_tem) 20 | else: 21 | ret.append(''.join(str_set)) 22 | str_set.pop() 23 | 24 | permutation(s) 25 | return ret 26 | 27 | 28 | if __name__ == '__main__': 29 | s = 'abc' 30 | print my_permutation(s) 31 | print [''.join(p) for p in permutations(s)] 32 | -------------------------------------------------------------------------------- /fourth/fourth/twenty_seven.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 将二叉搜索树转化成一个排序的双向链表,只调整树中结点的指向,不用新结点 4 | 中序遍历,根结点的left指向左子树的最后一个(最大)值,right指向右子树的(最小)值 5 | """ 6 | 7 | from collections import deque 8 | 9 | 10 | class TreeNode(object): 11 | def __init__(self, x): 12 | self.val = x 13 | self.left = None 14 | self.right = None 15 | 16 | 17 | class Tree(object): 18 | """ 19 | 非二叉搜索树,建树的时候values中的顺序需要注意 20 | 之后有时间会改成二叉搜索树 21 | """ 22 | def __init__(self): 23 | self.root = None 24 | 25 | def construct_tree(self, values=None): 26 | # 结点值不存在的话,values中用None表示 27 | if not values: 28 | return None 29 | self.root = TreeNode(values[0]) 30 | queue = deque([self.root]) 31 | leng = len(values) 32 | nums = 1 33 | while nums < leng: 34 | node = queue.popleft() 35 | if node: 36 | node.left = TreeNode(values[nums]) if values[nums] else None 37 | queue.append(node.left) 38 | if nums + 1 < leng: 39 | node.right = TreeNode(values[nums + 1]) if values[nums + 1] else None 40 | queue.append(node.right) 41 | nums += 1 42 | nums += 1 43 | 44 | def bfs(self): 45 | ret = [] 46 | queue = deque([self.root]) 47 | while queue: 48 | node = queue.popleft() 49 | if node: 50 | ret.append(node.val) 51 | queue.append(node.left) 52 | queue.append(node.right) 53 | return ret 54 | 55 | 56 | class Solution(object): 57 | 58 | @staticmethod 59 | def convert(tree): 60 | """结点转换""" 61 | if not tree: 62 | return None 63 | p_last = Solution.convert_nodes(tree, None) 64 | while p_last and p_last.left: # 获取链表头结点 65 | p_last = p_last.left 66 | return p_last 67 | 68 | @staticmethod 69 | def convert_nodes(tree, last): 70 | if not tree: 71 | return None 72 | if tree.left: 73 | last = Solution.convert_nodes(tree.left, last) 74 | if last: 75 | last.right = tree 76 | tree.left = last 77 | last = tree 78 | if tree.right: 79 | last = Solution.convert_nodes(tree.right, last) 80 | return last 81 | 82 | @staticmethod 83 | def print_nodes(tree): 84 | # 正序链表打印 85 | ret = [] 86 | while tree: 87 | tmp = [] 88 | tmp.append(tree.left.val if tree.left else None) 89 | tmp.append(tree.val) 90 | tmp.append(tree.right.val if tree.right else None) 91 | ret.append(tmp) 92 | tree = tree.right 93 | print ret 94 | 95 | if __name__ == '__main__': 96 | r = Tree() 97 | # r.construct_tree([2, 1]) 98 | # r.construct_tree([2, None, 3]) 99 | # r.construct_tree([2, 1, 3]) 100 | # r.construct_tree([]) 101 | r.construct_tree([5, 3, 6, 2, 4, None, 7, 1]) 102 | t = Solution.convert(r.root) 103 | Solution.print_nodes(t) 104 | 105 | -------------------------------------------------------------------------------- /fourth/fourth/twenty_six.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 复杂链表的复制 4 | 链表中除了指向后一个结点的指针之外,还有一个指针指向任意结点 5 | 分为三步完成: 6 | 一复制每个结点,并把新结点放在老结点后面,如1->2,复制为1->1->2->2 7 | 二为每个新结点设置other指针 8 | 三把复制后的结点链表拆开 9 | """ 10 | import random 11 | 12 | 13 | class Node(object): 14 | 15 | def __init__(self, val): 16 | self.val = val 17 | self.next = None 18 | self.other = None 19 | 20 | 21 | class Solution(object): 22 | 23 | @staticmethod 24 | def clone_nodes(head): 25 | # 结点复制 26 | move = head 27 | while move: 28 | tmp = Node(move.val) 29 | tmp.next = move.next 30 | move.next = tmp 31 | move = tmp.next 32 | return head 33 | 34 | @staticmethod 35 | def set_nodes(head): 36 | # other指针设置 37 | move = head 38 | while move: 39 | m_next = move.next 40 | if move.other: 41 | m_next.other = move.other.next 42 | move = m_next.next 43 | return head 44 | 45 | @staticmethod 46 | def reconstruct_nodes(head): 47 | # 结点拆分 48 | ret = head.next if head else Node 49 | move = ret 50 | while head: 51 | head = move.next 52 | if head: 53 | move.next = head.next 54 | move = move.next 55 | return ret 56 | 57 | @staticmethod 58 | def clone_link(head): 59 | # 结果 60 | h = Solution.clone_nodes(head) 61 | h = Solution.set_nodes(h) 62 | ret = Solution.reconstruct_nodes(h) 63 | return ret 64 | 65 | @staticmethod 66 | def print_nodes(head): 67 | # 打印结点值,结点other的值,用来比较 68 | ret = [] 69 | while head: 70 | tmp = [head.val] 71 | if head.other: 72 | tmp.append(head.other.val) 73 | ret.append(tmp) 74 | head = head.next 75 | print ret 76 | 77 | @staticmethod 78 | def construct_nodes(vals): 79 | """ 80 | 构造一个简单的复杂链表 81 | :param vals: list 82 | :return: Nodes 83 | """ 84 | if not vals: 85 | return Node 86 | move = head = Node(vals.pop(0)) 87 | nodes = [None, head] 88 | for v in vals: 89 | tmp = Node(v) 90 | move.next = tmp 91 | nodes.append(tmp) 92 | move = move.next 93 | # print [node.val for node in nodes if node] 94 | move = head 95 | while move: 96 | # 设置other指针为随机结点 97 | move.other = random.choice(nodes) 98 | move = move.next 99 | return head 100 | 101 | 102 | if __name__ == '__main__': 103 | link = Solution.construct_nodes([1, 2, 3, 4, 5]) 104 | Solution.print_nodes(link) 105 | test = Solution.clone_link(link) # 复制 106 | Solution.print_nodes(test) 107 | -------------------------------------------------------------------------------- /fourth/second/README.md: -------------------------------------------------------------------------------- 1 | # 4.2 画图让抽象问题形象化 2 | 3 | ## 面试题19 二叉树的镜像 4 | > 思路一:可以按层次遍历,每一层从右到左 5 | > 6 | > 思路二:使用递归 7 | 8 | ```python 9 | def mirror_bfs(root): 10 | ret = [] 11 | queue = deque([root]) 12 | while queue: 13 | node = queue.popleft() 14 | if node: 15 | ret.append(node.val) 16 | queue.append(node.right) 17 | queue.append(node.left) 18 | return ret 19 | 20 | 21 | def mirror_pre(root): 22 | ret = [] 23 | 24 | def traversal(root): 25 | if root: 26 | ret.append(root.val) 27 | traversal(root.right) 28 | traversal(root.left) 29 | traversal(root) 30 | return ret 31 | ``` 32 | 33 | ## 面试题20 顺时针打印矩阵 34 | > 每一圈的开始位置总是坐上角元素[0, 0], [1, 1]... 35 | 36 | ```python 37 | def print_matrix(matrix): 38 | """ 39 | :param matrix: [[]] 40 | """ 41 | rows = len(matrix) 42 | cols = len(matrix[0]) if matrix else 0 43 | start = 0 44 | ret = [] 45 | while start * 2 < rows and start * 2 < cols: 46 | print_circle(matrix, start, rows, cols, ret) 47 | start += 1 48 | print ret 49 | 50 | 51 | def print_circle(matrix, start, rows, cols, ret): 52 | row = rows - start - 1 # 最后一行 53 | col = cols - start - 1 54 | # left->right 55 | for c in range(start, col+1): 56 | ret.append(matrix[start][c]) 57 | # top->bottom 58 | if start < row: 59 | for r in range(start+1, row+1): 60 | ret.append(matrix[r][col]) 61 | # right->left 62 | if start < row and start < col: 63 | for c in range(start, col)[::-1]: 64 | ret.append(matrix[row][c]) 65 | # bottom->top 66 | if start < row and start < col: 67 | for r in range(start+1, row)[::-1]: 68 | ret.append(matrix[r][start]) 69 | ``` 70 | -------------------------------------------------------------------------------- /fourth/second/nineteen.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求二叉树的镜像 4 | 思路一:按层次遍历,每一层从右到左 5 | 思路二:递归遍历 6 | """ 7 | from collections import deque 8 | 9 | 10 | class TreeNode(object): 11 | def __init__(self, x): 12 | self.val = x 13 | self.left = None 14 | self.right = None 15 | 16 | 17 | class Tree(object): 18 | def __init__(self): 19 | self.root = None 20 | 21 | def construct_tree(self, values=None): 22 | if not values: 23 | return None 24 | self.root = TreeNode(values[0]) 25 | queue = deque([self.root]) 26 | leng = len(values) 27 | nums = 1 28 | while nums < leng: 29 | node = queue.popleft() 30 | if node: 31 | node.left = TreeNode(values[nums]) if values[nums] else None 32 | queue.append(node.left) 33 | if nums + 1 < leng: 34 | node.right = TreeNode(values[nums + 1]) if values[nums + 1] else None 35 | queue.append(node.right) 36 | nums += 1 37 | nums += 1 38 | 39 | def bfs(self): 40 | ret = [] 41 | queue = deque([self.root]) 42 | while queue: 43 | node = queue.popleft() 44 | if node: 45 | ret.append(node.val) 46 | queue.append(node.left) 47 | queue.append(node.right) 48 | return ret 49 | 50 | 51 | def mirror_bfs(root): 52 | ret = [] 53 | queue = deque([root]) 54 | while queue: 55 | node = queue.popleft() 56 | if node: 57 | ret.append(node.val) 58 | queue.append(node.right) 59 | queue.append(node.left) 60 | return ret 61 | 62 | 63 | def mirror_pre(root): 64 | ret = [] 65 | 66 | def traversal(root): 67 | if root: 68 | ret.append(root.val) 69 | traversal(root.right) 70 | traversal(root.left) 71 | traversal(root) 72 | return ret 73 | 74 | 75 | if __name__ == '__main__': 76 | t = Tree() 77 | t.construct_tree([1, 2, 6, 4, 3, 7, 5]) 78 | print t.bfs() 79 | print mirror_bfs(t.root) 80 | print mirror_pre(t.root) 81 | -------------------------------------------------------------------------------- /fourth/second/twenty.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 按从外到里的顺序顺时针打印矩阵 4 | 每一圈的开始位置总是坐上角元素[0, 0], [1, 1]... 5 | """ 6 | 7 | 8 | def print_matrix(matrix): 9 | """ 10 | :param matrix: [[]] 11 | """ 12 | rows = len(matrix) 13 | cols = len(matrix[0]) if matrix else 0 14 | start = 0 15 | ret = [] 16 | while start * 2 < rows and start * 2 < cols: 17 | print_circle(matrix, start, rows, cols, ret) 18 | start += 1 19 | print ret 20 | 21 | 22 | def print_circle(matrix, start, rows, cols, ret): 23 | row = rows - start - 1 # 最后一行 24 | col = cols - start - 1 25 | # left->right 26 | for c in range(start, col+1): 27 | ret.append(matrix[start][c]) 28 | # top->bottom 29 | if start < row: 30 | for r in range(start+1, row+1): 31 | ret.append(matrix[r][col]) 32 | # right->left 33 | if start < row and start < col: 34 | for c in range(start, col)[::-1]: 35 | ret.append(matrix[row][c]) 36 | # bottom->top 37 | if start < row and start < col: 38 | for r in range(start+1, row)[::-1]: 39 | ret.append(matrix[r][start]) 40 | 41 | 42 | if __name__ == '__main__': 43 | """ 44 | mat = [[1, 2, 3], 45 | [5, 6, 7], 46 | [9, 10, 11]] 47 | mat = [[]] 48 | mat = [[1]] 49 | mat = [[1, 2, 3, 4]] 50 | mat = [[1], [2], [3], [4]] 51 | """ 52 | mat = [[1, 2], 53 | [5, 6]] 54 | print_matrix(mat) 55 | -------------------------------------------------------------------------------- /fourth/third/README.md: -------------------------------------------------------------------------------- 1 | # 4.3 举例让抽象问题具体化 2 | 3 | ## 面试题21 包含min函数的栈 4 | > 要求:栈的push,pop,min操作的时间复杂度都是O(1) 5 | > 6 | > 思路:使用一个辅助栈保存最小值 7 | 8 | ```python 9 | class MyStack(object): 10 | 11 | def __init__(self): 12 | self.stack = [] 13 | self.min = [] 14 | 15 | def push(self, val): 16 | self.stack.append(val) 17 | if self.min and self.min[-1] < val: 18 | self.min.append(self.min[-1]) 19 | else: 20 | self.min.append(val) 21 | 22 | def pop(self): 23 | if self.stack: 24 | self.min.pop() 25 | return self.stack.pop() 26 | return None 27 | 28 | def min(self): 29 | return self.min[-1] if self.min else None 30 | ``` 31 | 32 | ## 面试题22 栈的压入弹出序列 33 | > 要求:判断给定的两个序列中,后者是不是前者的弹出序列,给定栈不包含相同值 34 | > 35 | > 思路:使用一个辅助栈, 如果辅助栈栈顶元素不等于出栈元素,则从入栈中找改值,直到入栈为空 36 | > 37 | > 如果最后出栈序列为空,则是入栈的弹出序列值 38 | > 39 | 40 | ```python 41 | def pop_order(push_stack, pop_stack): 42 | if not push_stack or not pop_stack: 43 | return False 44 | stack = [] 45 | while pop_stack: 46 | pop_val = pop_stack[0] 47 | if stack and stack[-1] == pop_val: 48 | stack.pop() 49 | pop_stack.pop(0) 50 | else: 51 | while push_stack: 52 | if push_stack[0] != pop_val: 53 | stack.append(push_stack.pop(0)) 54 | else: 55 | push_stack.pop(0) 56 | pop_stack.pop(0) 57 | break 58 | if not push_stack: 59 | while stack: 60 | if stack.pop() != pop_stack.pop(0): 61 | return False 62 | if not pop_stack: 63 | return True 64 | return False 65 | ``` 66 | 67 | ## 面试题23 从上往下打印二叉树 68 | > 思路:广度优先搜索,按层次遍历 69 | > 70 | 71 | ```python 72 | def bfs(tree): 73 | if not tree: 74 | return None 75 | stack = [tree] 76 | ret = [] 77 | while stack: 78 | node = stack.pop(0) 79 | ret.append(node.val) 80 | if node.left: 81 | stack.append(node.left) 82 | if node.right: 83 | stack.append(node.right) 84 | return ret 85 | ``` 86 | 87 | ## 面试题24 二叉搜索树的后序遍历序列 88 | > 要求:判断给定的整数数组是不是二叉搜索树的后序遍历序列 89 | > 90 | > 整数数组中不包含重复值 91 | > 92 | > 整数序列的最后一个值是根结点,然后比根结点小的值是左子树,剩下的是右子树,递归左右子树 93 | > 94 | 95 | ```python 96 | def is_post_order(order): 97 | length = len(order) 98 | if length: 99 | root = order[-1] 100 | left = 0 101 | while order[left] < root: 102 | left += 1 103 | right = left 104 | while right < length - 1: 105 | if order[right] < root: 106 | return False 107 | right += 1 108 | left_ret = True if left == 0 else is_post_order(order[:left]) 109 | right_ret = True if left == right else is_post_order(order[left:right]) 110 | return left_ret and right_ret 111 | return False 112 | ``` 113 | 114 | ## 面试题25 二叉树中和为某一值的路径 115 | > 要求:输入一棵二叉树和一个值,求从根结点到叶结点的和等于该值的路径 116 | > 117 | > 深度优先搜索变形 118 | > 119 | 120 | ```python 121 | def find_path(tree, num): 122 | ret = [] 123 | if not tree: 124 | return ret 125 | path = [tree] 126 | sums = [tree.val] 127 | 128 | def dfs(tree): 129 | if tree.left: 130 | path.append(tree.left) 131 | sums.append(sums[-1]+tree.left.val) 132 | dfs(tree.left) 133 | if tree.right: 134 | path.append(tree.right) 135 | sums.append(sums[-1] + tree.right.val) 136 | dfs(tree.right) 137 | if not tree.left and not tree.right: 138 | if sums[-1] == num: 139 | ret.append([p.val for p in path]) 140 | path.pop() 141 | sums.pop() 142 | 143 | dfs(tree) 144 | return ret 145 | ``` -------------------------------------------------------------------------------- /fourth/third/twenty_five.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 输入一棵二叉树和一个值,求从根结点到叶结点的和等于该值的路径 4 | 深度优先搜索变形 5 | """ 6 | 7 | 8 | from collections import deque 9 | 10 | 11 | class TreeNode(object): 12 | def __init__(self, x): 13 | self.val = x 14 | self.left = None 15 | self.right = None 16 | 17 | 18 | class Tree(object): 19 | def __init__(self): 20 | self.root = None 21 | 22 | def construct_tree(self, values=None): 23 | if not values: 24 | return None 25 | self.root = TreeNode(values[0]) 26 | queue = deque([self.root]) 27 | leng = len(values) 28 | nums = 1 29 | while nums < leng: 30 | node = queue.popleft() 31 | if node: 32 | node.left = TreeNode(values[nums]) if values[nums] else None 33 | queue.append(node.left) 34 | if nums + 1 < leng: 35 | node.right = TreeNode(values[nums + 1]) if values[nums + 1] else None 36 | queue.append(node.right) 37 | nums += 1 38 | nums += 1 39 | 40 | 41 | def find_path(tree, num): 42 | ret = [] 43 | if not tree: 44 | return ret 45 | path = [tree] 46 | sums = [tree.val] 47 | 48 | def dfs(tree): 49 | if tree.left: 50 | path.append(tree.left) 51 | sums.append(sums[-1]+tree.left.val) 52 | dfs(tree.left) 53 | if tree.right: 54 | path.append(tree.right) 55 | sums.append(sums[-1] + tree.right.val) 56 | dfs(tree.right) 57 | if not tree.left and not tree.right: 58 | if sums[-1] == num: 59 | ret.append([p.val for p in path]) 60 | path.pop() 61 | sums.pop() 62 | 63 | dfs(tree) 64 | return ret 65 | 66 | 67 | if __name__ == '__main__': 68 | t = Tree() 69 | t.construct_tree([1, 3, 6, 4, 3, 1, 1]) 70 | print find_path(t.root, 8) 71 | -------------------------------------------------------------------------------- /fourth/third/twenty_four.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 判断给定的整数数组是不是二叉搜索树的后序遍历序列 4 | 整数数组中不包含重复值 5 | 整数序列的最后一个值是根结点,然后比根结点小的值是左子树,剩下的是右子树,递归左右子树 6 | """ 7 | 8 | 9 | def is_post_order(order): 10 | length = len(order) 11 | if length: 12 | root = order[-1] 13 | left = 0 14 | while order[left] < root: 15 | left += 1 16 | right = left 17 | while right < length - 1: 18 | if order[right] < root: 19 | return False 20 | right += 1 21 | left_ret = True if left == 0 else is_post_order(order[:left]) 22 | right_ret = True if left == right else is_post_order(order[left:right]) 23 | return left_ret and right_ret 24 | return False 25 | 26 | 27 | if __name__ == '__main__': 28 | print is_post_order([9, 6, 7]) 29 | -------------------------------------------------------------------------------- /fourth/third/twenty_one.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 包含min函数的栈 4 | 栈的push,pop,min操作的时间复杂度都是O(1) 5 | 使用一个辅助栈保存最小值 6 | """ 7 | 8 | 9 | class MyStack(object): 10 | 11 | def __init__(self): 12 | self.stack = [] 13 | self.min = [] 14 | 15 | def push(self, val): 16 | self.stack.append(val) 17 | if self.min and self.min[-1] < val: 18 | self.min.append(self.min[-1]) 19 | else: 20 | self.min.append(val) 21 | 22 | def pop(self): 23 | if self.stack: 24 | self.min.pop() 25 | return self.stack.pop() 26 | return None 27 | 28 | def min(self): 29 | return self.min[-1] if self.min else None 30 | 31 | if __name__ == '__main__': 32 | s = MyStack() 33 | s.push(2) 34 | s.push(1) 35 | s.push(3) 36 | s.pop() 37 | s.push(2) 38 | print s.stack 39 | print s.min 40 | -------------------------------------------------------------------------------- /fourth/third/twenty_three.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 从上往下打印二叉树 4 | 树的广度优先,按层次遍历,使用一个辅助队列就可以 5 | """ 6 | 7 | 8 | from collections import deque 9 | 10 | 11 | class TreeNode(object): 12 | def __init__(self, x): 13 | self.val = x 14 | self.left = None 15 | self.right = None 16 | 17 | 18 | class Tree(object): 19 | def __init__(self): 20 | self.root = None 21 | 22 | def construct_tree(self, values=None): 23 | if not values: 24 | return None 25 | self.root = TreeNode(values[0]) 26 | queue = deque([self.root]) 27 | leng = len(values) 28 | nums = 1 29 | while nums < leng: 30 | node = queue.popleft() 31 | if node: 32 | node.left = TreeNode(values[nums]) if values[nums] else None 33 | queue.append(node.left) 34 | if nums + 1 < leng: 35 | node.right = TreeNode(values[nums + 1]) if values[nums + 1] else None 36 | queue.append(node.right) 37 | nums += 1 38 | nums += 1 39 | 40 | def bfs(self): 41 | ret = [] 42 | queue = deque([self.root]) 43 | while queue: 44 | node = queue.popleft() 45 | if node: 46 | ret.append(node.val) 47 | queue.append(node.left) 48 | queue.append(node.right) 49 | return ret 50 | 51 | 52 | def bfs(tree): 53 | if not tree: 54 | return None 55 | stack = [tree] 56 | ret = [] 57 | while stack: 58 | node = stack.pop(0) 59 | ret.append(node.val) 60 | if node.left: 61 | stack.append(node.left) 62 | if node.right: 63 | stack.append(node.right) 64 | return ret 65 | 66 | if __name__ == '__main__': 67 | t = Tree() 68 | t.construct_tree([1, 2, 6, 4, 3, 7, 5]) 69 | print t.bfs() 70 | print bfs(t.root) 71 | -------------------------------------------------------------------------------- /fourth/third/twenty_two.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 栈的压入弹出序列,判断给定的两个序列中,后者是不是前者的弹出序列 4 | 序列中不存在相同值 5 | 使用一个辅助栈, 如果辅助栈栈顶元素不等于出栈元素,则从入栈中找改值,直到入栈为空 6 | 如果最后出栈序列为空,则是入栈的弹出序列 7 | """ 8 | 9 | 10 | def pop_order(push_stack, pop_stack): 11 | if not push_stack or not pop_stack: 12 | return False 13 | stack = [] 14 | while pop_stack: 15 | pop_val = pop_stack[0] 16 | if stack and stack[-1] == pop_val: 17 | stack.pop() 18 | pop_stack.pop(0) 19 | else: 20 | while push_stack: 21 | if push_stack[0] != pop_val: 22 | stack.append(push_stack.pop(0)) 23 | else: 24 | push_stack.pop(0) 25 | pop_stack.pop(0) 26 | break 27 | if not push_stack: 28 | while stack: 29 | if stack.pop() != pop_stack.pop(0): 30 | return False 31 | if not pop_stack: 32 | return True 33 | return False 34 | 35 | 36 | if __name__ == '__main__': 37 | print pop_order([1, 2, 3], [2, 3, 1]) 38 | -------------------------------------------------------------------------------- /second/README.md: -------------------------------------------------------------------------------- 1 | # 第2章 面试需要的基础知识 2 | 3 | ## 2.2 [编程语言](./second) 4 | > #### 面试题2 [使用Python实现单例模式](./second#面试题2-使用Python实现单例模式) 5 | 6 | ## 2.3 [数据结构](./third) 7 | > #### 面试题3 [二维数组中的查找](./third#面试题3-二维数组中的查找) 8 | > #### 面试题4 [替换空格](./third#面试题4-替换空格) 9 | > #### 面试题5 [从尾到头打印单链表](./third#面试题5-从尾到头打印单链表) 10 | > #### 面试题6 [重建二叉树](./third#面试题6-重建二叉树) 11 | > #### 面试题7 [用两个栈实现队列](./third#面试题7-用两个栈实现队列) 12 | 13 | ## 2.4 [算法和数据操作](./fourth) 14 | > #### 面试题8 [旋转数组的最小数字](./fourth#面试题8-旋转数组的最小数字) 15 | > #### 面试题9 [斐波那契数列](./fourth#面试题9-斐波那契数列) 16 | > #### 面试题10 [二进制中1的个数](./fourth#面试题10-二进制中1的个数) 17 | 18 | -------------------------------------------------------------------------------- /second/fourth/README.md: -------------------------------------------------------------------------------- 1 | # 算法和数据操作 2 | 3 | ## 面试题8 旋转数组的最小数字 4 | > 要求:把递增数组的前面部分数字移到队尾,求数组中的最小值,例如[3,4,5,6,1,2] 5 | > 6 | > 思路:使用二分法,但要考虑[1, 0, 0, 1]这种数据,只能顺序查找 7 | 8 | ```python 9 | def find_min(nums): 10 | if not nums: 11 | return False 12 | length = len(nums) 13 | left, right = 0, length - 1 14 | while nums[left] >= nums[right]: 15 | if right - left == 1: 16 | return nums[right] 17 | mid = (left + right) / 2 18 | if nums[left] == nums[mid] == nums[right]: 19 | return min(nums) 20 | if nums[left] <= nums[mid]: 21 | left = mid 22 | if nums[right] >= nums[mid]: 23 | right = mid 24 | return nums[0] 25 | ``` 26 | 27 | ## 面试题9 斐波那契数列 28 | > 思路:用生成器 29 | 30 | ```python 31 | def fib(num): 32 | a, b = 0, 1 33 | for i in xrange(num): 34 | yield b 35 | a, b = b, a + b 36 | ``` 37 | 38 | ## 面试题10 二进制中1的个数 39 | > 要求:求一个整数的二进制表示中,1的个数 40 | > 41 | > 思路:二进制表示中,最后的那个1被减去后,低位都变为0,高位不变,按位与就可以去掉这个1 42 | 43 | 44 | ```python 45 | def num_of_1(n): 46 | ret = 0 47 | while n: 48 | ret += 1 49 | n = n & n-1 50 | return ret 51 | ``` 52 | -------------------------------------------------------------------------------- /second/fourth/eight.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求旋转数组中的最小值 4 | 二分法 5 | 需要考虑[1, 0, 0, 1]这种数据,只能从头查找 6 | """ 7 | 8 | 9 | def find_min(nums): 10 | if not nums: 11 | return False 12 | length = len(nums) 13 | left, right = 0, length - 1 14 | while nums[left] >= nums[right]: 15 | if right - left == 1: 16 | return nums[right] 17 | mid = (left + right) / 2 18 | if nums[left] == nums[mid] == nums[right]: 19 | return min(nums) 20 | if nums[left] <= nums[mid]: 21 | left = mid 22 | if nums[right] >= nums[mid]: 23 | right = mid 24 | return nums[0] 25 | 26 | if __name__ == '__main__': 27 | print find_min([2, 2, 4, 5, 6, 2]) 28 | print find_min([1, 0, 0, 1]) 29 | -------------------------------------------------------------------------------- /second/fourth/nine.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 斐波那契数列 4 | 直接使用生成器, 节省内存 5 | """ 6 | 7 | 8 | def fib(num): 9 | a, b = 0, 1 10 | for i in xrange(num): 11 | yield b 12 | a, b = b, a + b 13 | 14 | 15 | if __name__ == '__main__': 16 | print [n for n in fib(10)] 17 | -------------------------------------------------------------------------------- /second/fourth/ten.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求一个整数的二进制表示中,1的个数 4 | 二进制表示中,最后的那个1被减去后,低位都变为0,高位不变,按位与就可以去掉这个1 5 | """ 6 | 7 | 8 | def num_of_1(n): 9 | ret = 0 10 | while n: 11 | ret += 1 12 | n = n & n-1 13 | return ret 14 | 15 | if __name__ == '__main__': 16 | print bin(100).count('1') == num_of_1(100) 17 | -------------------------------------------------------------------------------- /second/second/README.md: -------------------------------------------------------------------------------- 1 | # 编程语言 2 | 3 | ## 面试题2 使用Python实现单例模式 4 | 5 | ### 方法一 使用__new__实现单例模式 6 | > 使用__new__实现单例模式,具体我对__new__的理解可以点[这里](http://www.cnblogs.com/qiaojushuang/p/7805973.html) 7 | ```python 8 | class SingleTon(object): 9 | _instance = {} 10 | 11 | def __new__(cls, *args, **kwargs): 12 | if cls not in cls._instance: 13 | cls._instance[cls] = super(SingleTon, cls).__new__(cls, *args, **kwargs) 14 | # print cls._instance 15 | return cls._instance[cls] 16 | 17 | 18 | class MyClass(SingleTon): 19 | class_val = 22 20 | 21 | def __init__(self, val): 22 | self.val = val 23 | 24 | def obj_fun(self): 25 | print self.val, 'obj_fun' 26 | 27 | @staticmethod 28 | def static_fun(): 29 | print 'staticmethod' 30 | 31 | @classmethod 32 | def class_fun(cls): 33 | print cls.class_val, 'classmethod' 34 | 35 | 36 | if __name__ == '__main__': 37 | a = MyClass(1) 38 | b = MyClass(2) 39 | print a is b # True 40 | print id(a), id(b) # 4367665424 4367665424 41 | # 类型验证 42 | print type(a) # 43 | print type(b) # 44 | ``` 45 | 46 | ### 方法二 使用装饰器实现单例模式 47 | ```python 48 | from functools import wraps 49 | 50 | 51 | def single_ton(cls): 52 | _instance = {} 53 | 54 | @wraps(cls) 55 | def single(*args, **kwargs): 56 | if cls not in _instance: 57 | _instance[cls] = cls(*args, **kwargs) 58 | return _instance[cls] 59 | return single 60 | 61 | 62 | @single_ton 63 | class SingleTon(object): 64 | val = 123 65 | 66 | def __init__(self, a): 67 | self.a = a 68 | 69 | if __name__ == '__main__': 70 | s = SingleTon(1) 71 | t = SingleTon(2) 72 | print s is t 73 | print s.a, t.a 74 | print s.val, t.val 75 | ``` 76 | 77 | ### 方法三 使用模块实现单例模式 78 | > 可以使用模块创建单例模式,然后在其他模块中导入该单例,这个需要所有人遵守导入规则,不然就没法实现单例了 79 | 80 | ```python 81 | # use_module.py 82 | class SingleTon(object): 83 | 84 | def __init__(self, val): 85 | self.val = val 86 | 87 | single = SingleTon(2) 88 | 89 | # test_module.py 90 | from use_module import single 91 | 92 | a = single 93 | b = single 94 | print a.val, b.val 95 | print a is b 96 | a.val = 233 97 | print a.val, b.val 98 | 99 | ``` 100 | 101 | ### 方法四 使用metaclass实现单例模式 102 | > 目前我对元类还了解不深,以后来填坑 103 | -------------------------------------------------------------------------------- /second/second/test_module.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # test_module.py 3 | from use_module import single 4 | 5 | 6 | a = single 7 | b = single 8 | print a.val, b.val 9 | print a is b 10 | a.val = 233 11 | print a.val, b.val 12 | -------------------------------------------------------------------------------- /second/second/use_decorator.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 使用装饰器实现单例模式 4 | """ 5 | from functools import wraps 6 | 7 | 8 | def single_ton(cls): 9 | _instance = {} 10 | 11 | @wraps(cls) 12 | def single(*args, **kwargs): 13 | if cls not in _instance: 14 | _instance[cls] = cls(*args, **kwargs) 15 | return _instance[cls] 16 | return single 17 | 18 | 19 | @single_ton 20 | class SingleTon(object): 21 | val = 123 22 | 23 | def __init__(self, a): 24 | self.a = a 25 | 26 | if __name__ == '__main__': 27 | s = SingleTon(1) 28 | t = SingleTon(2) 29 | print s is t 30 | print s.a, t.a 31 | print s.val, t.val 32 | -------------------------------------------------------------------------------- /second/second/use_module.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # use_module.py 3 | 4 | 5 | class SingleTon(object): 6 | 7 | def __init__(self, val): 8 | self.val = val 9 | 10 | 11 | single = SingleTon(2) 12 | -------------------------------------------------------------------------------- /second/second/use_new.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 使用__new__实现单例模式 4 | """ 5 | 6 | 7 | class SingleTon(object): 8 | _instance = {} 9 | 10 | def __new__(cls, *args, **kwargs): 11 | if cls not in cls._instance: 12 | cls._instance[cls] = super(SingleTon, cls).__new__(cls, *args, **kwargs) 13 | # print cls._instance 14 | return cls._instance[cls] 15 | 16 | 17 | class MyClass(SingleTon): 18 | class_val = 22 19 | 20 | def __init__(self, val): 21 | self.val = val 22 | 23 | def obj_fun(self): 24 | print self.val, 'obj_fun' 25 | 26 | @staticmethod 27 | def static_fun(): 28 | print 'staticmethod' 29 | 30 | @classmethod 31 | def class_fun(cls): 32 | print cls.class_val, 'classmethod' 33 | 34 | 35 | if __name__ == '__main__': 36 | a = MyClass(1) 37 | b = MyClass(2) 38 | print a is b # True 39 | print id(a), id(b) # 4367665424 4367665424 40 | # 类型验证 41 | print type(a) # 42 | print type(b) # 43 | # 实例方法 44 | a.obj_fun() # 2 obj_fun 45 | b.obj_fun() # 2 obj_fun 46 | # 类方法 47 | MyClass.class_fun() # 22 classmethod 48 | a.class_fun() # 22 classmethod 49 | b.class_fun() # 22 classmethod 50 | # 静态方法 51 | MyClass.static_fun() # staticmethod 52 | a.static_fun() # staticmethod 53 | b.static_fun() # staticmethod 54 | # 类变量 55 | a.class_val = 33 56 | print MyClass.class_val # 22 57 | print a.class_val # 33 58 | print b.class_val # 33 59 | # 实例变量 60 | print b.val # 2 61 | print a.val # 2 62 | -------------------------------------------------------------------------------- /second/third/README.md: -------------------------------------------------------------------------------- 1 | # 数据结构 2 | 3 | ## 面试题3 二维数组中的查找 [LeetCode](https://leetcode.com/problems/search-a-2d-matrix-ii/) 4 | > 题目:二维数组中,每行从左到右递增,每列从上到下递增,给出一个数,判断它是否在数组中 5 | > 6 | > 思路:从左下角或者右上角开始比较 7 | 8 | ```python 9 | def find_integer(matrix, num): 10 | """ 11 | :param matrix: [[]] 12 | :param num: int 13 | :return: bool 14 | """ 15 | if not matrix: 16 | return False 17 | rows, cols = len(matrix), len(matrix[0]) 18 | row, col = rows - 1, 0 19 | while row >= 0 and col <= cols - 1: 20 | if matrix[row][col] == num: 21 | return True 22 | elif matrix[row][col] > num: 23 | row -= 1 24 | else: 25 | col += 1 26 | return False 27 | ``` 28 | 29 | ## 面试题4 替换空格 30 | > 题目:把字符串中的空格替换成'20%' 31 | > 32 | >方法1:直接使用Python字符串的内置函数 33 | 34 | ```python 35 | >>> ' a b '.replace(' ', '20%') 36 | ``` 37 | > 方法2: 使用正则表达式 38 | 39 | ```python 40 | >>> import re 41 | >>> ret = re.compile(' ') 42 | >>> ret.sub('20%', ' a b ') 43 | ``` 44 | 45 | ## 面试题5 从尾到头打印单链表 46 | > 方法1:使用栈,可以使用列表模拟 47 | 48 | ```python 49 | def print_links(links): 50 | stack = [] 51 | while links: 52 | stack.append(links.val) 53 | links = links.next 54 | while stack: 55 | print stack.pop() 56 | ``` 57 | > 方法2:直接递归 58 | 59 | ```python 60 | def print_link_recursion(links): 61 | if links: 62 | print_link_recursion(links.next) 63 | print links.val 64 | ``` 65 | 66 | ## 面试题6 重建二叉树 [LeetCode](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) 67 | > 要求:用前序和中序遍历结果构建二叉树,遍历结果中不包含重复值 68 | > 69 | > 思路:前序的第一个元素是根结点的值,在中序中找到该值,中序中该值的左边的元素是根结点的左子树,右边是右子树,然后递归的处理左边和右边 70 | > 71 | > **提示**:二叉树结点,以及对二叉树的各种操作,测试代码见six.py 72 | ```python 73 | def construct_tree(preorder=None, inorder=None): 74 | """ 75 | 构建二叉树 76 | """ 77 | if not preorder or not inorder: 78 | return None 79 | index = inorder.index(preorder[0]) 80 | left = inorder[0:index] 81 | right = inorder[index+1:] 82 | root = TreeNode(preorder[0]) 83 | root.left = construct_tree(preorder[1:1+len(left)], left) 84 | root.right = construct_tree(preorder[-len(right):], right) 85 | return root 86 | ``` 87 | 88 | ## 面试题7 用两个栈实现队列 89 | > 要求:用两个栈实现队列,分别实现入队和出队操作 90 | > 思路:一个栈负责入队,另一个负责出队,出栈为空则从入栈中导入到出栈中 91 | 92 | ```python 93 | class MyQueue(object): 94 | def __init__(self): 95 | self.stack = [] 96 | self.stack2 = [] 97 | 98 | def push(self, val): 99 | self.stack.append(val) 100 | 101 | def pop(self): 102 | if self.stack2: 103 | return self.stack2.pop() 104 | while self.stack: 105 | self.stack2.append(self.stack.pop()) 106 | return self.stack2.pop() if self.stack2 else u'队列为空' 107 | ``` -------------------------------------------------------------------------------- /second/third/five.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 从尾到头打印单链表 4 | 思路1:使用栈 5 | 思路2:递归 6 | """ 7 | 8 | 9 | class ListNode(object): 10 | def __init__(self, x): 11 | self.val = x 12 | self.next = None 13 | 14 | 15 | class Link(object): 16 | 17 | @staticmethod 18 | def link(values): 19 | head = ListNode(0) 20 | move = head 21 | try: 22 | for val in values: 23 | tmp = ListNode(val) 24 | move.next = tmp 25 | move = move.next 26 | except Exception as e: 27 | print e 28 | return head.next 29 | 30 | 31 | def print_links(links): 32 | stack = [] 33 | while links: 34 | stack.append(links.val) 35 | links = links.next 36 | while stack: 37 | print stack.pop() 38 | 39 | 40 | def print_link_recursion(links): 41 | if links: 42 | print_link_recursion(links.next) 43 | print links.val 44 | 45 | if __name__ == '__main__': 46 | head = Link.link([1, 2, 3, 4, 5, 6]) 47 | # print_links(head) 48 | print_link_recursion(head) 49 | -------------------------------------------------------------------------------- /second/third/seven.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 用两个栈实现队列 4 | """ 5 | 6 | 7 | class MyQueue(object): 8 | def __init__(self): 9 | self.stack = [] 10 | self.stack2 = [] 11 | 12 | def push(self, val): 13 | self.stack.append(val) 14 | 15 | def pop(self): 16 | if self.stack2: 17 | return self.stack2.pop() 18 | while self.stack: 19 | self.stack2.append(self.stack.pop()) 20 | return self.stack2.pop() if self.stack2 else u'队列为空' 21 | 22 | 23 | if __name__ == '__main__': 24 | q = MyQueue() 25 | q.push(1) 26 | q.push(2) 27 | print q.pop() 28 | q.push(3) 29 | print q.pop() 30 | q.push(4) 31 | print q.pop() 32 | print q.pop() 33 | print q.pop() 34 | -------------------------------------------------------------------------------- /second/third/six.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | """ 4 | 使用先序遍历和中序遍历的结果重建二叉树 5 | """ 6 | from collections import deque 7 | 8 | 9 | class TreeNode(object): 10 | """ 11 | 二叉树结点定义 12 | """ 13 | def __init__(self, x): 14 | self.val = x 15 | self.left = None 16 | self.right = None 17 | 18 | 19 | class Tree(object): 20 | """ 21 | 二叉树 22 | """ 23 | def __init__(self): 24 | self.root = None 25 | 26 | def bfs(self): 27 | ret = [] 28 | queue = deque([self.root]) 29 | while queue: 30 | node = queue.popleft() 31 | if node: 32 | ret.append(node.val) 33 | queue.append(node.left) 34 | queue.append(node.right) 35 | return ret 36 | 37 | def pre_traversal(self): 38 | ret = [] 39 | 40 | def traversal(head): 41 | if not head: 42 | return 43 | ret.append(head.val) 44 | traversal(head.left) 45 | traversal(head.right) 46 | 47 | traversal(self.root) 48 | return ret 49 | 50 | def in_traversal(self): 51 | ret = [] 52 | 53 | def traversal(head): 54 | if not head: 55 | return 56 | traversal(head.left) 57 | ret.append(head.val) 58 | traversal(head.right) 59 | 60 | traversal(self.root) 61 | return ret 62 | 63 | def post_traversal(self): 64 | ret = [] 65 | 66 | def traversal(head): 67 | if not head: 68 | return 69 | traversal(head.left) 70 | traversal(head.right) 71 | ret.append(head.val) 72 | 73 | traversal(self.root) 74 | return ret 75 | 76 | 77 | def construct_tree(preorder=None, inorder=None): 78 | """ 79 | 构建二叉树 80 | """ 81 | if not preorder or not inorder: 82 | return None 83 | index = inorder.index(preorder[0]) 84 | left = inorder[0:index] 85 | right = inorder[index+1:] 86 | root = TreeNode(preorder[0]) 87 | root.left = construct_tree(preorder[1:1+len(left)], left) 88 | root.right = construct_tree(preorder[-len(right):], right) 89 | return root 90 | 91 | 92 | if __name__ == '__main__': 93 | t = Tree() 94 | root = construct_tree([1, 2, 4, 7, 3, 5, 6, 8], [4, 7, 2, 1, 5, 3, 8, 6]) 95 | t.root = root 96 | print t.bfs() 97 | print t.pre_traversal() 98 | print t.in_traversal() 99 | print t.post_traversal() 100 | 101 | -------------------------------------------------------------------------------- /second/third/three.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # 二维数组中,每行从左到右递增,每列从上到下递增,给出一个数,判断它是否在数组中 3 | # 从左下角(或右上角)开始遍历数组 4 | 5 | 6 | def find_integer(matrix, num): 7 | """ 8 | :param matrix: [[]] 9 | :param num: int 10 | :return: bool 11 | """ 12 | if not matrix: 13 | return False 14 | rows, cols = len(matrix), len(matrix[0]) 15 | row, col = rows - 1, 0 16 | while row >= 0 and col <= cols - 1: 17 | if matrix[row][col] == num: 18 | return True 19 | elif matrix[row][col] > num: 20 | row -= 1 21 | else: 22 | col += 1 23 | return False 24 | 25 | 26 | if __name__ == '__main__': 27 | matrix = [[1, 2, 3], 28 | [2, 3, 6], 29 | [3, 6, 7]] 30 | num = 6 31 | print find_integer(matrix, num) 32 | -------------------------------------------------------------------------------- /seventh/README.md: -------------------------------------------------------------------------------- 1 | # 第7章 两个面试案例 2 | 3 | ## 7.1 [案例一](./first) 4 | > #### 面试题49 [把字符串转化成整数](./first#面试题49-把字符串转化成整数) 5 | 6 | ## 7.2 [案例二](./second) 7 | > #### 面试题50 [树中两个结点的最低公共祖先](./second#面试题50-树中两个结点的最低公共祖先) 8 | -------------------------------------------------------------------------------- /seventh/first/README.md: -------------------------------------------------------------------------------- 1 | # 7.1 案例一 2 | 3 | ## 面试题49 把字符串转化成整数 4 | > 要求:把字符串转化成整数 5 | > 6 | > 测试用例:正负数和0,空字符,包含其他字符 7 | > 8 | > 备注:使用raise抛出异常作为非法提示 9 | 10 | ```python 11 | def str_to_int(string): 12 | if not string: # 空字符返回异常 13 | raise Exception('string cannot be None', string) 14 | flag = 0 # 用来表示第一个字符是否为+、- 15 | ret = 0 # 结果 16 | for k, s in enumerate(string): 17 | if s.isdigit(): # 数字直接运算 18 | val = ord(s) - ord('0') 19 | ret = ret * 10 + val 20 | else: 21 | if not flag: 22 | if s == '+' and k == 0: # 避免中间出现+、- 23 | flag = 1 24 | elif s == '-' and k == 0: 25 | flag = -1 26 | else: 27 | raise Exception('digit is need', string) 28 | else: 29 | raise Exception('digit is need', string) 30 | if flag and len(string) == 1: # 判断是不是只有+、- 31 | raise Exception('digit is need', string) 32 | return ret if flag >= 0 else -ret 33 | ``` 34 | -------------------------------------------------------------------------------- /seventh/first/fourty_nine.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 把字符串转化成整数 4 | 测试用例:正负数和0,空字符,包含其他字符 5 | 备注:使用raise抛出异常作为非法提示 6 | """ 7 | 8 | 9 | def str_to_int(string): 10 | if not string: # 空字符返回异常 11 | raise Exception('string cannot be None', string) 12 | flag = 0 # 用来表示第一个字符是否为+、- 13 | ret = 0 # 结果 14 | for k, s in enumerate(string): 15 | if s.isdigit(): # 数字直接运算 16 | val = ord(s) - ord('0') 17 | ret = ret * 10 + val 18 | else: 19 | if not flag: 20 | if s == '+' and k == 0: # 避免中间出现+、- 21 | flag = 1 22 | elif s == '-' and k == 0: 23 | flag = -1 24 | else: 25 | raise Exception('digit is need', string) 26 | else: 27 | raise Exception('digit is need', string) 28 | if flag and len(string) == 1: # 判断是不是只有+、- 29 | raise Exception('digit is need', string) 30 | return ret if flag >= 0 else -ret 31 | 32 | 33 | if __name__ == '__main__': 34 | test = '12399+' 35 | print str_to_int(test) 36 | -------------------------------------------------------------------------------- /seventh/second/README.md: -------------------------------------------------------------------------------- 1 | # 7.2 案例二 2 | 3 | ## 面试题50 树中两个结点的最低公共祖先 4 | > 要求:求普通二叉树中两个结点的最低公共祖先 5 | > 6 | >方法一:先求出两个结点到根结点的路径,然后从路径中找出最后一个公共结点 7 | > 8 | >备注:文件fifty.py中包含该代码的具体测试数据 9 | 10 | ```python 11 | class Solution(object): 12 | 13 | def __init__(self, root, node1, node2): 14 | self.root = root # 树的根结点 15 | self.node1 = node1 16 | self.node2 = node2 # 需要求的两个结点 17 | 18 | @staticmethod 19 | def get_path(root, node, ret): 20 | """获取结点的路径""" 21 | if not root or not node: 22 | return False 23 | ret.append(root) 24 | if root == node: 25 | return True 26 | left = Solution.get_path(root.left, node, ret) 27 | right = Solution.get_path(root.right, node, ret) 28 | if left or right: 29 | return True 30 | ret.pop() 31 | 32 | def get_last_common_node(self): 33 | """获取公共结点""" 34 | route1 = [] 35 | route2 = [] # 保存结点路径 36 | ret1 = Solution.get_path(self.root, self.node1, route1) 37 | ret2 = Solution.get_path(self.root, self.node2, route2) 38 | ret = None 39 | if ret1 and ret2: # 路径比较 40 | length = len(route1) if len(route1) <= len(route2) else len(route2) 41 | index = 0 42 | while index < length: 43 | if route1[index] == route2[index]: 44 | ret = route1[index] 45 | index += 1 46 | return ret 47 | ``` 48 | -------------------------------------------------------------------------------- /seventh/second/fifty.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求普通二叉树中两个结点的最低公共祖先 4 | 先求出两个结点到根结点的路径,然后从路径中找出最后一个公共结点 5 | """ 6 | from collections import deque 7 | 8 | 9 | class TreeNode(object): 10 | """树结点""" 11 | def __init__(self, x): 12 | self.val = x 13 | self.left = None 14 | self.right = None 15 | 16 | 17 | class Tree(object): 18 | def __init__(self): 19 | self.root = None 20 | self.nodes = [] # 树中的结点 21 | 22 | def construct_tree(self, values=None): 23 | """使用列表构造二叉树""" 24 | if not values: 25 | return None 26 | self.root = TreeNode(values[0]) 27 | self.nodes.append(self.root) 28 | queue = deque([self.root]) 29 | leng = len(values) 30 | nums = 1 31 | while nums < leng: 32 | node = queue.popleft() 33 | if node: 34 | node.left = TreeNode(values[nums]) if values[nums] else None 35 | queue.append(node.left) 36 | self.nodes.append(node.left) 37 | if nums + 1 < leng: 38 | node.right = TreeNode(values[nums + 1]) if values[nums + 1] else None 39 | queue.append(node.right) 40 | self.nodes.append(node.right) 41 | nums += 1 42 | nums += 1 43 | 44 | def get_node(self, index): 45 | """根据索引返回树中的某个结点""" 46 | if index >= len(self.nodes): 47 | return None 48 | return self.nodes[index] 49 | 50 | 51 | class Solution(object): 52 | 53 | def __init__(self, root, node1, node2): 54 | self.root = root # 树的根结点 55 | self.node1 = node1 56 | self.node2 = node2 # 需要求的两个结点 57 | 58 | @staticmethod 59 | def get_path(root, node, ret): 60 | """获取结点的路径""" 61 | if not root or not node: 62 | return False 63 | ret.append(root) 64 | if root == node: 65 | return True 66 | left = Solution.get_path(root.left, node, ret) 67 | right = Solution.get_path(root.right, node, ret) 68 | if left or right: 69 | return True 70 | ret.pop() 71 | 72 | def get_last_common_node(self): 73 | """获取公共结点""" 74 | route1 = [] 75 | route2 = [] # 保存结点路径 76 | ret1 = Solution.get_path(self.root, self.node1, route1) 77 | ret2 = Solution.get_path(self.root, self.node2, route2) 78 | ret = None 79 | if ret1 and ret2: # 路径比较 80 | length = len(route1) if len(route1) <= len(route2) else len(route2) 81 | index = 0 82 | while index < length: 83 | if route1[index] == route2[index]: 84 | ret = route1[index] 85 | index += 1 86 | return ret 87 | 88 | if __name__ == '__main__': 89 | vals = [0, 1, 2, 3, 4, 5, 6, 7] 90 | tree = Tree() 91 | tree.construct_tree(vals) 92 | r = tree.root # 树的根结点 93 | n1 = tree.get_node(7) # 结点1 94 | n2 = tree.get_node(4) # 结点2 95 | s = Solution(r, n1, n2) 96 | parent = s.get_last_common_node() # 公共结点 97 | print parent, parent.val if parent else None 98 | -------------------------------------------------------------------------------- /sixth/README.md: -------------------------------------------------------------------------------- 1 | # 第6章 面试中的各项能力 2 | 3 | ## 6.3 [知识迁移能力](./third) 4 | > #### 面试题38 [数字在排序数组中出现的次数](./third#面试题38-数字在排序数组中出现的次数) 5 | > #### 面试题39 [二叉树的深度](./third#面试题39-二叉树的深度) 6 | > #### 面试题40 [数组中只出现一次的数字](./third#面试题40-数组中只出现一次的数字) 7 | > #### 面试题41 [和为s的两个数字VS和为s的连续正数序列](./third#面试题41-和为s的两个数字vs和为s的连续正数序列) 8 | > #### 面试题42 [翻转单词顺序与左旋转字符串](./third#面试题42-翻转单词顺序与左旋转字符串) 9 | 10 | ## 6.4 [抽象建模能力](./fourth) 11 | > #### 面试题43 [n个骰子的点数](./fourth#面试题43-n个骰子的点数) 12 | > #### 面试题44 [扑克牌的顺子](./fourth#面试题44-扑克牌的顺子) 13 | > #### 面试题45 [圆圈中最后剩下的数字](./fourth#面试题45-圆圈中最后剩下的数字) 14 | 15 | ## 6.5 [发散思维能力](./fifth) 16 | > #### 面试题46 [求1+2...+n](./fifth#面试题46-求1+2...+n) 17 | > #### 面试题47 [不用加减乘除做加法](./fifth#面试题47-不用加减乘除做加法) 18 | > #### 面试题48 [不能被继承的类](./fifth#面试题48-不能被继承的类) 19 | 20 | 21 | -------------------------------------------------------------------------------- /sixth/fifth/README.md: -------------------------------------------------------------------------------- 1 | # 6.5 发散思维能力 2 | 3 | ## 面试题46 求1+2...+n 4 | > 要求:不能使用乘除、for、while、if、else等 5 | > 6 | >方法一:使用range和sum 7 | > 8 | >方法二:使用reduce 9 | 10 | ```python 11 | def get_sum1(n): 12 | return sum(range(1, n+1)) 13 | 14 | 15 | def get_sum2(n): 16 | return reduce(lambda x, y: x+y, range(1, n+1)) 17 | ``` 18 | 19 | ## 面试题47 不用加减乘除做加法 20 | > 要求:不用加减乘除做加法 21 | > 22 | >方法一:使用位运算,Python中大整数会自动处理,因此对carry需要加个判断 23 | > 24 | >方法二:使用sum 25 | 26 | ```python 27 | def bit_add(n1, n2): 28 | carry = 1 29 | while carry: 30 | s = n1 ^ n2 31 | carry = 0xFFFFFFFF & ((n1 & n2) << 1) 32 | carry = -(~(carry - 1) & 0xFFFFFFFF) if carry > 0x7FFFFFFF else carry 33 | n1 = s 34 | n2 = carry 35 | return n1 36 | 37 | 38 | def add(n1, n2): 39 | return sum([n1, n2]) 40 | ``` 41 | 42 | ## 面试题48 不能被继承的类 43 | >Python中不知道怎么实现不能被继承的类。以后补充代码或者原因。 44 | -------------------------------------------------------------------------------- /sixth/fifth/fourty_seven.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 不用加减乘除做加法 4 | 方法一:使用位运算,Python中大整数会自动处理,因此对carry需要加个判断 5 | 方法二:使用sum 6 | """ 7 | 8 | 9 | def bit_add(n1, n2): 10 | carry = 1 11 | while carry: 12 | s = n1 ^ n2 13 | carry = 0xFFFFFFFF & ((n1 & n2) << 1) 14 | carry = -(~(carry - 1) & 0xFFFFFFFF) if carry > 0x7FFFFFFF else carry 15 | n1 = s 16 | n2 = carry 17 | return n1 18 | 19 | 20 | def add(n1, n2): 21 | return sum([n1, n2]) 22 | 23 | if __name__ == '__main__': 24 | a = 222 25 | b = -199 26 | print bit_add(a, b) 27 | print add(a, b) 28 | -------------------------------------------------------------------------------- /sixth/fifth/fourty_six.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 不能使用乘除、for、while、if、else等 4 | 方法一:使用range和sum 5 | 方法二:使用reduce 6 | """ 7 | 8 | 9 | def get_sum1(n): 10 | return sum(range(1, n+1)) 11 | 12 | 13 | def get_sum2(n): 14 | return reduce(lambda x, y: x+y, range(1, n+1)) 15 | 16 | 17 | if __name__ == '__main__': 18 | print get_sum1(4) 19 | print get_sum2(40) 20 | -------------------------------------------------------------------------------- /sixth/fourth/README.md: -------------------------------------------------------------------------------- 1 | # 6.4 抽象建模能力 2 | 3 | ## 面试题43 n个骰子的点数 4 | > 要求:求出n个骰子朝上一面之和s所有可能值出现的概率 5 | > 6 | > 思路:n出现的可能是前面n-1到n-6出现可能的和,设置两个数组,分别保存每一轮 7 | 8 | ```python 9 | def get_probability(n): 10 | if n < 1: 11 | return [] 12 | data1 = [0] + [1] * 6 + [0] * 6 * (n - 1) 13 | data2 = [0] + [0] * 6 * n # 开头多一个0,方便按照习惯从1计数 14 | flag = 0 15 | for v in range(2, n+1): # 控制次数 16 | if flag: 17 | for k in range(v, 6*v+1): 18 | data1[k] = sum([data2[k-j] for j in range(1, 7) if k > j]) 19 | flag = 0 20 | else: 21 | for k in range(v, 6*v+1): 22 | data2[k] = sum([data1[k-j] for j in range(1, 7) if k > j]) 23 | flag = 1 24 | ret = [] 25 | total = 6 ** n 26 | data = data2[n:] if flag else data1[n:] 27 | for v in data: 28 | ret.append(v*1.0/total) 29 | print data 30 | return ret 31 | ``` 32 | 33 | ## 面试题44 扑克牌的顺子 34 | > 要求:从扑克牌中随机抽取5张牌,判断是不是顺子,大小王可以当任意值 35 | > 36 | > 思路: 使用排序 37 | 38 | ```python 39 | import random 40 | 41 | 42 | def is_continus(nums, k): 43 | data = [random.choice(nums) for _ in range(k)] 44 | data.sort() 45 | print data 46 | zero = data.count(0) 47 | small, big = zero, zero + 1 48 | while big < k: 49 | if data[small] == data[big]: 50 | return False 51 | tmp = data[big] - data[small] 52 | if tmp > 1: 53 | if tmp - 1 > zero: 54 | return False 55 | else: 56 | zero -= tmp - 1 57 | small += 1 58 | big += 1 59 | else: 60 | small += 1 61 | big += 1 62 | return True 63 | ``` 64 | 65 | ## 面试题45 圆圈中最后剩下的数字 66 | > 要求:0到n-1排成一圈,从0开始每次数m个数删除,求最后剩余的数 67 | > 68 | > 思路:当 n > 1 时: f(n,m) = [f(n-1, m)+m]%n,当 n = 1 时: f(n,m)=0,*关键是推导出关系表达式* 69 | 70 | ```python 71 | def last_num(n, m): 72 | ret = 0 73 | if n == 1: 74 | return 0 75 | for i in range(2, n+1): 76 | ret = (m + ret) % i 77 | return ret 78 | ``` 79 | 80 | -------------------------------------------------------------------------------- /sixth/fourth/fourty_five.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 0到n-1排成一圈,从0开始每次数m个数删除,求最后剩余的数 4 | 当 n > 1 时: f(n,m) = [f(n-1, m)+m]%n,当 n = 1 时: f(n,m)=0 5 | """ 6 | 7 | 8 | def last_num(n, m): 9 | ret = 0 10 | if n == 1: 11 | return 0 12 | for i in range(2, n+1): 13 | ret = (m + ret) % i 14 | return ret 15 | 16 | if __name__ == '__main__': 17 | print last_num(3, 4) 18 | -------------------------------------------------------------------------------- /sixth/fourth/fourty_four.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 从扑克牌中随机抽取5张牌,判断是不是顺子,大小王可以当任意值 4 | 使用排序 5 | """ 6 | import random 7 | 8 | 9 | def is_continus(nums, k): 10 | data = [random.choice(nums) for _ in range(k)] 11 | data.sort() 12 | print data 13 | zero = data.count(0) 14 | small, big = zero, zero + 1 15 | while big < k: 16 | if data[small] == data[big]: 17 | return False 18 | tmp = data[big] - data[small] 19 | if tmp > 1: 20 | if tmp - 1 > zero: 21 | return False 22 | else: 23 | zero -= tmp - 1 24 | small += 1 25 | big += 1 26 | else: 27 | small += 1 28 | big += 1 29 | return True 30 | 31 | if __name__ == '__main__': 32 | test = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 33 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 34 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 35 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36 | 0, 0] 37 | t = 5 38 | print is_continus(test, t) 39 | -------------------------------------------------------------------------------- /sixth/fourth/fourty_three.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求出n个骰子朝上一面之和s所有可能值出现的概率 4 | n出现的可能是前面n-1到n-6出现可能的和,设置两个数组,分别保存每一轮 5 | """ 6 | 7 | 8 | def get_probability(n): 9 | if n < 1: 10 | return [] 11 | data1 = [0] + [1] * 6 + [0] * 6 * (n - 1) 12 | data2 = [0] + [0] * 6 * n # 开头多一个0,方便按照习惯从1计数 13 | flag = 0 14 | for v in range(2, n+1): # 控制次数 15 | if flag: 16 | for k in range(v, 6*v+1): 17 | data1[k] = sum([data2[k-j] for j in range(1, 7) if k > j]) 18 | flag = 0 19 | else: 20 | for k in range(v, 6*v+1): 21 | data2[k] = sum([data1[k-j] for j in range(1, 7) if k > j]) 22 | flag = 1 23 | ret = [] 24 | total = 6 ** n 25 | data = data2[n:] if flag else data1[n:] 26 | for v in data: 27 | ret.append(v*1.0/total) 28 | print data 29 | return ret 30 | 31 | if __name__ == '__main__': 32 | print get_probability(3) 33 | 34 | -------------------------------------------------------------------------------- /sixth/third/README.md: -------------------------------------------------------------------------------- 1 | # 6.3 知识迁移能力 2 | 3 | ## 面试题38 数字在排序数组中出现的次数 4 | > 思路: 使用二分法分别找到数组中第一个和最后一个出现的值的坐标,然后相减 5 | 6 | ```python 7 | def get_k_counts(nums, k): 8 | first = get_first_k(nums, k) 9 | last = get_last_k(nums, k) 10 | if first < 0 and last < 0: 11 | return 0 12 | if first < 0 or last < 0: 13 | return 1 14 | return last - first + 1 15 | 16 | 17 | def get_first_k(nums, k): 18 | left, right = 0, len(nums) - 1 19 | while left <= right: 20 | mid = (left + right) / 2 21 | if nums[mid] < k: 22 | if mid + 1 < len(nums) and nums[mid+1] == k: 23 | return mid + 1 24 | left = mid + 1 25 | elif nums[mid] == k: 26 | if mid - 1 < 0 or (mid - 1 >= 0 and nums[mid-1] < k): 27 | return mid 28 | right = mid - 1 29 | else: 30 | right = mid - 1 31 | return -1 32 | 33 | 34 | def get_last_k(nums, k): 35 | left, right = 0, len(nums) - 1 36 | while left <= right: 37 | mid = (left + right) / 2 38 | if nums[mid] < k: 39 | left = mid + 1 40 | elif nums[mid] == k: 41 | if mid + 1 == len(nums) or (mid + 1 < len(nums) and nums[mid+1] > k): 42 | return mid 43 | left = mid + 1 44 | else: 45 | if mid - 1 >= 0 and nums[mid-1] == k: 46 | return mid - 1 47 | right = mid - 1 48 | return -1 49 | ``` 50 | 51 | 52 | ## 面试题39 二叉树的深度 53 | > 思路: 分别递归的求左右子树的深度 54 | 55 | ```python 56 | def get_depth(tree): 57 | if not tree: 58 | return 0 59 | if not tree.left and not tree.right: 60 | return 1 61 | return 1 + max(get_depth(tree.left), get_depth(tree.right)) 62 | ``` 63 | 64 | ## 面试题40 数组中只出现一次的数字 65 | > 要求:数组中除了两个只出现一次的数字外,其他数字都出现了两遍 66 | > 67 | > 思路: 按位异或,在得到的值中找到二进制最后一个1,然后把数组按照该位是0还是1分为两组 68 | 69 | ```python 70 | def get_only_one_number(nums): 71 | if not nums: 72 | return None 73 | tmp_ret = 0 74 | for n in nums: # 获取两个值的异或结果 75 | tmp_ret ^= n 76 | last_one = get_bin(tmp_ret) 77 | a_ret, b_ret = 0, 0 78 | for n in nums: 79 | if is_one(n, last_one): 80 | a_ret ^= n 81 | else: 82 | b_ret ^= n 83 | return [a_ret, b_ret] 84 | 85 | 86 | def get_bin(num): # 得到第一个1 87 | ret = 0 88 | while num & 1 == 0 and ret < 32: 89 | num = num >> 1 90 | ret += 1 91 | return ret 92 | 93 | 94 | def is_one(num, t): # 验证t位是不是1 95 | num = num >> t 96 | return num & 0x01 97 | ``` 98 | 99 | ## 面试题41 和为s的两个数字VS和为s的连续正数序列 100 | ### 和为s的两个数字 101 | > 要求:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使其和为s 102 | > 103 | > 思路: 设置头尾两个指针,和大于s,尾指针减小,否砸头指针增加 104 | 105 | ```python 106 | def sum_to_s(nums, s): 107 | head, end = 0, len(nums) - 1 108 | while head < end: 109 | if nums[head] + nums[end] == s: 110 | return [nums[head], nums[end]] 111 | elif nums[head] + nums[end] > s: 112 | end -= 1 113 | else: 114 | head += 1 115 | return None 116 | ``` 117 | ### 和为s的连续整数序列 118 | > 要求:输入一个正数s, 打印出所有和为s的正整数序列(至少两个数) 119 | > 120 | > 思路: 使用两个指针,和比s小,大指针后移,比s大,小指针后移 121 | 122 | ```python 123 | def sum_to_s(s): 124 | a, b = 1, 2 125 | ret = [] 126 | while a < s / 2 + 1: 127 | if sum(range(a, b+1)) == s: 128 | ret.append(range(a, b+1)) 129 | a += 1 130 | elif sum(range(a, b+1)) < s: 131 | b += 1 132 | else: 133 | a += 1 134 | return ret 135 | ``` 136 | 137 | ## 面试题42 翻转单词顺序与左旋转字符串 138 | ### 翻转单词顺序 139 | > 要求:翻转一个英文句子中的单词顺序,标点和普通字符一样处理 140 | > 141 | > 思路: Python中字符串是不可变对象,不能用书中的方法,可以直接转化成列表然后转回去 142 | 143 | ```python 144 | def reverse_words(sentence): 145 | tmp = sentence.split() 146 | return ' '.join(tmp[::-1]) # 使用join效率更好,+每次都会创建新的字符串 147 | ``` 148 | ### 左旋转字符串 149 | > 思路: 把字符串的前面的若干位移到字符串的后面 150 | 151 | ```python 152 | def rotate_string(s, n): 153 | if not s: 154 | return '' 155 | n %= len(s) 156 | return s[n:] + s[:n] 157 | ``` -------------------------------------------------------------------------------- /sixth/third/fourty.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 数组中除了两个只出现一次的数字外,其他数字都出现了两遍 4 | 按位异或,在得到的值中找到二进制最后一个1,然后把数组按照该位是0还是1分为两组 5 | """ 6 | 7 | 8 | def get_only_one_number(nums): 9 | if not nums: 10 | return None 11 | tmp_ret = 0 12 | for n in nums: # 获取两个值的异或结果 13 | tmp_ret ^= n 14 | last_one = get_bin(tmp_ret) 15 | a_ret, b_ret = 0, 0 16 | for n in nums: 17 | if is_one(n, last_one): 18 | a_ret ^= n 19 | else: 20 | b_ret ^= n 21 | return [a_ret, b_ret] 22 | 23 | 24 | def get_bin(num): # 得到第一个1 25 | ret = 0 26 | while num & 1 == 0 and ret < 32: 27 | num = num >> 1 28 | ret += 1 29 | return ret 30 | 31 | 32 | def is_one(num, t): # 验证t位是不是1 33 | num = num >> t 34 | return num & 0x01 35 | 36 | 37 | if __name__ == '__main__': 38 | test = [1, 2, 3, 4, 3, 1, -1, -1] 39 | print get_only_one_number(test) 40 | -------------------------------------------------------------------------------- /sixth/third/fourty_one_a.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使其和为s 4 | 设置头尾两个指针,和大于s,尾指针减小,否砸头指针增加 5 | """ 6 | 7 | 8 | def sum_to_s(nums, s): 9 | head, end = 0, len(nums) - 1 10 | while head < end: 11 | if nums[head] + nums[end] == s: 12 | return [nums[head], nums[end]] 13 | elif nums[head] + nums[end] > s: 14 | end -= 1 15 | else: 16 | head += 1 17 | return None 18 | 19 | if __name__ == '__main__': 20 | test = [-4, 0, 1, 2, 4, 6, 8, 10, 12, 15, 18] 21 | s = 12 22 | print sum_to_s(test, s) 23 | -------------------------------------------------------------------------------- /sixth/third/fourty_one_b.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 输入一个正数s, 打印出所有和为s的正整数序列(至少两个数) 4 | 使用两个指针,和比s小,大指针后移,比s大,小指针后移 5 | """ 6 | 7 | 8 | def sum_to_s(s): 9 | a, b = 1, 2 10 | ret = [] 11 | while a < s / 2 + 1: 12 | if sum(range(a, b+1)) == s: 13 | ret.append(range(a, b+1)) 14 | a += 1 15 | elif sum(range(a, b+1)) < s: 16 | b += 1 17 | else: 18 | a += 1 19 | return ret 20 | 21 | if __name__ == '__main__': 22 | test = 199 23 | print sum_to_s(test) 24 | -------------------------------------------------------------------------------- /sixth/third/fourty_two_a.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 翻转一个英文句子中的单词顺序,标点和普通字符一样处理 4 | Python中字符串是不可变对象,不能用书中的方法,可以直接转化成列表然后转回去 5 | """ 6 | 7 | 8 | def reverse_words(sentence): 9 | tmp = sentence.split() 10 | return ' '.join(tmp[::-1]) # 使用join效率更好,+每次都会创建新的字符串 11 | 12 | if __name__ == '__main__': 13 | test = 'I am a engineer.' 14 | print reverse_words(test) 15 | -------------------------------------------------------------------------------- /sixth/third/fourty_two_b.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 把字符串的前面的若干位移到字符串的后面 4 | """ 5 | 6 | 7 | def rotate_string(s, n): 8 | if not s: 9 | return '' 10 | n %= len(s) 11 | return s[n:] + s[:n] 12 | 13 | if __name__ == '__main__': 14 | test = 'abcdefg' 15 | print rotate_string(test, 1) 16 | -------------------------------------------------------------------------------- /sixth/third/thirty_eight.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 统计一个数字在排序数组中出现的次数 4 | 使用二分法分别找到数组中第一个和最后一个出现的值的坐标,然后相减 5 | """ 6 | 7 | 8 | def get_k_counts(nums, k): 9 | first = get_first_k(nums, k) 10 | last = get_last_k(nums, k) 11 | if first < 0 and last < 0: 12 | return 0 13 | if first < 0 or last < 0: 14 | return 1 15 | return last - first + 1 16 | 17 | 18 | def get_first_k(nums, k): 19 | left, right = 0, len(nums) - 1 20 | while left <= right: 21 | mid = (left + right) / 2 22 | if nums[mid] < k: 23 | if mid + 1 < len(nums) and nums[mid+1] == k: 24 | return mid + 1 25 | left = mid + 1 26 | elif nums[mid] == k: 27 | if mid - 1 < 0 or (mid - 1 >= 0 and nums[mid-1] < k): 28 | return mid 29 | right = mid - 1 30 | else: 31 | right = mid - 1 32 | return -1 33 | 34 | 35 | def get_last_k(nums, k): 36 | left, right = 0, len(nums) - 1 37 | while left <= right: 38 | mid = (left + right) / 2 39 | if nums[mid] < k: 40 | left = mid + 1 41 | elif nums[mid] == k: 42 | if mid + 1 == len(nums) or (mid + 1 < len(nums) and nums[mid+1] > k): 43 | return mid 44 | left = mid + 1 45 | else: 46 | if mid - 1 >= 0 and nums[mid-1] == k: 47 | return mid - 1 48 | right = mid - 1 49 | return -1 50 | 51 | if __name__ == '__main__': 52 | test = [1, 2, 2, 3, 3, 3, 4] 53 | print get_k_counts(test, 5) 54 | -------------------------------------------------------------------------------- /sixth/third/thirty_nine.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求二叉树的深度 4 | 分别递归的求左右子树的深度 5 | """ 6 | from collections import deque 7 | 8 | 9 | def get_depth(tree): 10 | if not tree: 11 | return 0 12 | if not tree.left and not tree.right: 13 | return 1 14 | return 1 + max(get_depth(tree.left), get_depth(tree.right)) 15 | 16 | 17 | class TreeNode(object): 18 | def __init__(self, x): 19 | self.val = x 20 | self.left = None 21 | self.right = None 22 | 23 | 24 | class Tree(object): 25 | def __init__(self): 26 | self.root = None 27 | 28 | def construct_tree(self, values=None): 29 | if not values: 30 | return None 31 | self.root = TreeNode(values[0]) 32 | queue = deque([self.root]) 33 | leng = len(values) 34 | nums = 1 35 | while nums < leng: 36 | node = queue.popleft() 37 | if node: 38 | node.left = TreeNode(values[nums]) if values[nums] else None 39 | queue.append(node.left) 40 | if nums + 1 < leng: 41 | node.right = TreeNode(values[nums + 1]) if values[nums + 1] else None 42 | queue.append(node.right) 43 | nums += 1 44 | nums += 1 45 | 46 | def bfs(self): 47 | ret = [] 48 | queue = deque([self.root]) 49 | while queue: 50 | node = queue.popleft() 51 | if node: 52 | ret.append(node.val) 53 | queue.append(node.left) 54 | queue.append(node.right) 55 | return ret 56 | 57 | 58 | def bfs(tree): 59 | if not tree: 60 | return None 61 | stack = [tree] 62 | ret = [] 63 | while stack: 64 | node = stack.pop(0) 65 | ret.append(node.val) 66 | if node.left: 67 | stack.append(node.left) 68 | if node.right: 69 | stack.append(node.right) 70 | return ret 71 | 72 | if __name__ == '__main__': 73 | t = Tree() 74 | t.construct_tree([1, 2, 3]) 75 | print t.bfs() 76 | print get_depth(t.root) 77 | -------------------------------------------------------------------------------- /third/README.md: -------------------------------------------------------------------------------- 1 | # 第3章 高质量的代码 2 | 3 | ## 3.3 [代码的完整性](./third) 4 | > #### 面试题11 [数值的整数次方](./third#面试题11-数值的整数次方) 5 | > #### 面试题12 [打印1到最大的n位数](./third#面试题12-打印1到最大的n位数) 6 | > #### 面试题13 [O(1)时间删除链表结点](./third#面试题13-o1时间删除链表结点) 7 | > #### 面试题14 [调整数组顺序使寄数位于偶数前面](./third#面试题14-调整数组顺序使奇数位于偶数前面) 8 | 9 | ## 3.4 [代码的鲁棒性](./fourth) 10 | > #### 面试题15 [链表中倒数第k个结点](./fourth#面试题15-链表中倒数第k个结点) 11 | > #### 面试题16 [反转链表](./fourth#面试题16-反转链表) 12 | > #### 面试题17 [合并两个排序的链表](./fourth#面试题17-合并两个排序的链表) 13 | > #### 面试题18 [树的子结构](./third#面试题18-树的子结构) 14 | -------------------------------------------------------------------------------- /third/fourth/README.md: -------------------------------------------------------------------------------- 1 | # 3.4 代码的鲁棒性 2 | 3 | ## 面试题15 链表中倒数第k个结点 4 | > 要求:求单链表中的倒数第k个结点 5 | > 6 | > 思路:使用快慢指针,快的先走k-1步,需要考虑空链表以及k为0 7 | 8 | ```python 9 | def last_kth(link, k): 10 | if not link or k <= 0: 11 | return None 12 | move = link 13 | while move and k-1 >= 0: 14 | move = move.next 15 | k -= 1 16 | while move: 17 | move = move.next 18 | link = link.next 19 | if k == 0: 20 | return link.val 21 | return None 22 | ``` 23 | 24 | ## 面试题16 反转链表 25 | > 要求:反转链表 26 | > 27 | > 思路:需要考虑空链表,只有一个结点的链表 28 | 29 | ```python 30 | def reverse_link(head): 31 | if not head or not head.next: 32 | return head 33 | then = head.next 34 | head.next = None 35 | last = then.next 36 | while then: 37 | then.next = head 38 | head = then 39 | then = last 40 | if then: 41 | last = then.next 42 | return head 43 | ``` 44 | 45 | ## 面试题17 合并两个排序的链表 46 | > 要求:合并两个排序的链表 47 | > 48 | > 思路:使用递归 49 | 50 | ```python 51 | def merge_link(head1, head2): 52 | if not head1: 53 | return head2 54 | if not head2: 55 | return head1 56 | if head1.val <= head2.val: 57 | ret = head1 58 | ret.next = merge_link(head1.next, head2) 59 | else: 60 | ret = head2 61 | ret.next = merge_link(head1, head2.next) 62 | return ret 63 | 64 | ``` 65 | 66 | ## 面试题18 树的子结构 67 | > 要求:判断一棵二叉树是不是另一个的子结构 68 | > 69 | > 思路:使用递归 70 | 71 | ```python 72 | def sub_tree(tree1, tree2): 73 | if tree1 and tree2: 74 | if tree1.val == tree2.val: 75 | return sub_tree(tree1.left, tree2.left) and sub_tree(tree1.right, tree2.right) 76 | else: 77 | return sub_tree(tree1.left, tree2) or sub_tree(tree1.right, tree2) 78 | if not tree1 and tree2: 79 | return False 80 | return True 81 | ``` 82 | -------------------------------------------------------------------------------- /third/fourth/eighteen.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 树的子结构 4 | 判断一棵二叉树是不是另一棵的子结构 5 | """ 6 | 7 | from collections import deque 8 | 9 | 10 | class TreeNode(object): 11 | def __init__(self, x): 12 | self.val = x 13 | self.left = None 14 | self.right = None 15 | 16 | 17 | class Tree(object): 18 | def __init__(self): 19 | self.root = None 20 | 21 | def construct_tree(self, values=None): 22 | if not values: 23 | return None 24 | self.root = TreeNode(values[0]) 25 | queue = deque([self.root]) 26 | leng = len(values) 27 | nums = 1 28 | while nums < leng: 29 | node = queue.popleft() 30 | if node: 31 | node.left = TreeNode(values[nums]) if values[nums] else None 32 | queue.append(node.left) 33 | if nums + 1 < leng: 34 | node.right = TreeNode(values[nums + 1]) if values[nums + 1] else None 35 | queue.append(node.right) 36 | nums += 1 37 | nums += 1 38 | 39 | def bfs(self): 40 | ret = [] 41 | queue = deque([self.root]) 42 | while queue: 43 | node = queue.popleft() 44 | if node: 45 | ret.append(node.val) 46 | queue.append(node.left) 47 | queue.append(node.right) 48 | return ret 49 | 50 | def pre_traversal(self): 51 | ret = [] 52 | 53 | def traversal(head): 54 | if not head: 55 | return 56 | ret.append(head.val) 57 | traversal(head.left) 58 | traversal(head.right) 59 | 60 | traversal(self.root) 61 | return ret 62 | 63 | def in_traversal(self): 64 | ret = [] 65 | 66 | def traversal(head): 67 | if not head: 68 | return 69 | traversal(head.left) 70 | ret.append(head.val) 71 | traversal(head.right) 72 | 73 | traversal(self.root) 74 | return ret 75 | 76 | def post_traversal(self): 77 | ret = [] 78 | 79 | def traversal(head): 80 | if not head: 81 | return 82 | traversal(head.left) 83 | traversal(head.right) 84 | ret.append(head.val) 85 | 86 | traversal(self.root) 87 | return ret 88 | 89 | 90 | def sub_tree(tree1, tree2): 91 | if tree1 and tree2: 92 | if tree1.val == tree2.val: 93 | return sub_tree(tree1.left, tree2.left) and sub_tree(tree1.right, tree2.right) 94 | else: 95 | return sub_tree(tree1.left, tree2) or sub_tree(tree1.right, tree2) 96 | if not tree1 and tree2: 97 | return False 98 | return True 99 | 100 | 101 | if __name__ == '__main__': 102 | t1 = Tree() 103 | t1.construct_tree([1, 2, 3, 4, 5]) 104 | print t1.bfs() 105 | t2 = Tree() 106 | t2.construct_tree([2, 4, 5]) 107 | print t2.bfs() 108 | print sub_tree(t1.root, t2.root) 109 | -------------------------------------------------------------------------------- /third/fourth/fifteen.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 链表中倒数第k个结点 4 | 使用快慢指针,快的先走k-1步,需要考虑控链表以及k为0 5 | """ 6 | 7 | 8 | def last_kth(link, k): 9 | if not link or k <= 0: 10 | return None 11 | move = link 12 | while move and k-1 >= 0: 13 | move = move.next 14 | k -= 1 15 | while move: 16 | move = move.next 17 | link = link.next 18 | if k == 0: 19 | return link.val 20 | return None 21 | 22 | 23 | class ListNode(object): 24 | def __init__(self, x): 25 | self.val = x 26 | self.next = None 27 | 28 | 29 | class Nodes(object): 30 | def __init__(self, values=None): 31 | self.nodes = self._set_link(values) if values else None 32 | 33 | def get_link(self): 34 | return self.nodes 35 | 36 | def _set_link(self, values): 37 | head = ListNode(0) 38 | move = head 39 | try: 40 | for val in values: 41 | tmp = ListNode(val) 42 | move.next = tmp 43 | move = move.next 44 | except Exception as e: 45 | print e 46 | return head.next 47 | 48 | 49 | if __name__ == '__main__': 50 | nodes = Nodes((1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 22)) 51 | link = nodes.get_link() 52 | print last_kth(link, 12) 53 | -------------------------------------------------------------------------------- /third/fourth/seventeen.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 合并两个排序的链表 4 | 使用递归 5 | """ 6 | 7 | 8 | def merge_link(head1, head2): 9 | if not head1: 10 | return head2 11 | if not head2: 12 | return head1 13 | if head1.val <= head2.val: 14 | ret = head1 15 | ret.next = merge_link(head1.next, head2) 16 | else: 17 | ret = head2 18 | ret.next = merge_link(head1, head2.next) 19 | return ret 20 | 21 | 22 | class ListNode(object): 23 | def __init__(self, x): 24 | self.val = x 25 | self.next = None 26 | 27 | 28 | class Nodes(object): 29 | def __init__(self, values=None): 30 | self.nodes = self._set_link(values) if values else None 31 | 32 | def get_link(self): 33 | return self.nodes 34 | 35 | def print_self(self): 36 | Nodes.print_link(self.nodes) 37 | 38 | @staticmethod 39 | def print_link(link=None): 40 | count = 1 41 | while link: 42 | if count == 1: 43 | print link.val, 44 | elif count % 5 == 0: 45 | print '->', link.val 46 | else: 47 | print '->', link.val, 48 | count += 1 49 | link = link.next 50 | print 51 | 52 | def _set_link(self, values): 53 | head = ListNode(0) 54 | move = head 55 | try: 56 | for val in values: 57 | tmp = ListNode(val) 58 | move.next = tmp 59 | move = move.next 60 | except Exception as e: 61 | print e 62 | return head.next 63 | 64 | 65 | if __name__ == '__main__': 66 | nodes = Nodes([]) 67 | h1 = nodes.get_link() 68 | h2 = Nodes([2, 4, 5, 6, 7, 10]).get_link() 69 | ret = merge_link(h1, h2) 70 | Nodes.print_link(ret) 71 | -------------------------------------------------------------------------------- /third/fourth/sixteen.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 反转链表 4 | 需要考虑空链表,只有一个结点的链表 5 | """ 6 | 7 | 8 | def reverse_link(head): 9 | if not head or not head.next: 10 | return head 11 | then = head.next 12 | head.next = None 13 | last = then.next 14 | while then: 15 | then.next = head 16 | head = then 17 | then = last 18 | if then: 19 | last = then.next 20 | return head 21 | 22 | 23 | class ListNode(object): 24 | def __init__(self, x): 25 | self.val = x 26 | self.next = None 27 | 28 | 29 | class Nodes(object): 30 | def __init__(self, values=None): 31 | self.nodes = self._set_link(values) if values else None 32 | 33 | def get_link(self): 34 | return self.nodes 35 | 36 | def print_self(self): 37 | Nodes.print_link(self.nodes) 38 | 39 | @staticmethod 40 | def print_link(link=None): 41 | count = 1 42 | while link: 43 | if count == 1: 44 | print link.val, 45 | elif count % 5 == 0: 46 | print '->', link.val 47 | else: 48 | print '->', link.val, 49 | count += 1 50 | link = link.next 51 | print 52 | 53 | def _set_link(self, values): 54 | head = ListNode(0) 55 | move = head 56 | try: 57 | for val in values: 58 | tmp = ListNode(val) 59 | move.next = tmp 60 | move = move.next 61 | except Exception as e: 62 | print e 63 | return head.next 64 | 65 | 66 | if __name__ == '__main__': 67 | nodes = Nodes([1, 2, 3]) 68 | link = nodes.get_link() 69 | nodes.print_self() 70 | head = reverse_link(link) 71 | nodes.nodes = head 72 | Nodes.print_link(head) 73 | nodes.print_self() 74 | -------------------------------------------------------------------------------- /third/third/README.md: -------------------------------------------------------------------------------- 1 | # 3.3 代码的完整性 2 | 3 | ## 面试题11 数值的整数次方 4 | > 要求:求一个数的整数次方 5 | > 6 | > 思路:需要考虑次方是正数、负数和0,基数是0 7 | > 8 | > 浮点数相等不能直接用== 9 | 10 | ```python 11 | def power(base, exponent): 12 | if equal_zero(base) and exponent < 0: 13 | raise ZeroDivisionError 14 | ret = power_value(base, abs(exponent)) 15 | if exponent < 0: 16 | return 1.0 / ret 17 | else: 18 | return ret 19 | 20 | 21 | def equal_zero(num): 22 | if abs(num - 0.0) < 0.0000001: 23 | return True 24 | 25 | 26 | def power_value(base, exponent): 27 | if exponent == 0: 28 | return 1 29 | if exponent == 1: 30 | return base 31 | ret = power_value(base, exponent >> 1) 32 | ret *= ret 33 | if exponent & 1 == 1: 34 | ret *= base 35 | return ret 36 | ``` 37 | 38 | ## 面试题12 打印1到最大的n位数 39 | > 要求:输入n,打印出从1到最大的n位数 40 | > 41 | > 思路:Python中已经对大整数可以进行自动转换了,所以不需要考虑大整数溢出问题 42 | 43 | ```python 44 | def print_max_n(n): 45 | for i in xrange(10 ** n): 46 | print i 47 | ``` 48 | 49 | ## 面试题13 O(1)时间删除链表结点 50 | > 要求:O(1)时间删除链表结点 51 | > 52 | > 思路:如果有后续结点,后续结点的值前移,删除后续结点,如果没有,只能顺序查找了 53 | 54 | ```python 55 | def delete_node(link, node): 56 | if node == link: # 只有一个结点 57 | del node 58 | if node.next is None: # node是尾结点 59 | while link: 60 | if link.next == node: 61 | link.next = None 62 | link = link.next 63 | else: 64 | node.val = node.next.val 65 | n_node = node.next 66 | node.next = n_node.next 67 | del n_node 68 | ``` 69 | ## 面试题14 调整数组顺序使奇数位于偶数前面 70 | > 思路:使用两个指针,前后各一个,为了更好的扩展性,可以把判断奇偶部分抽取出来 71 | 72 | ```python 73 | def reorder(nums, func): 74 | left, right = 0, len(nums) - 1 75 | while left < right: 76 | while not func(nums[left]): 77 | left += 1 78 | while func(nums[right]): 79 | right -= 1 80 | if left < right: 81 | nums[left], nums[right] = nums[right], nums[left] 82 | 83 | 84 | def is_even(num): 85 | return (num & 1) == 0 86 | ``` -------------------------------------------------------------------------------- /third/third/eleven.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 求数值的整数次方 4 | 需要考虑正数、负数和0 5 | 浮点数不能直接用==比较 6 | """ 7 | 8 | 9 | def power(base, exponent): 10 | if equal_zero(base) and exponent < 0: 11 | raise ZeroDivisionError 12 | ret = power_value(base, abs(exponent)) 13 | if exponent < 0: 14 | return 1.0 / ret 15 | else: 16 | return ret 17 | 18 | 19 | def equal_zero(num): 20 | if abs(num - 0.0) < 0.0000001: 21 | return True 22 | 23 | 24 | def power_value(base, exponent): 25 | if exponent == 0: 26 | return 1 27 | if exponent == 1: 28 | return base 29 | ret = power_value(base, exponent >> 1) 30 | ret *= ret 31 | if exponent & 1 == 1: 32 | ret *= base 33 | return ret 34 | 35 | if __name__ == '__main__': 36 | # print power(0.0, -1) 37 | print power(-2, -6) 38 | -------------------------------------------------------------------------------- /third/third/fourteen.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 调整数组顺序使奇数位于偶数前面 4 | 使用两个指针,前后各一个,为了更好的扩展性,可以把判断奇偶部分抽取出来 5 | """ 6 | 7 | 8 | def reorder(nums, func): 9 | left, right = 0, len(nums) - 1 10 | while left < right: 11 | while not func(nums[left]): 12 | left += 1 13 | while func(nums[right]): 14 | right -= 1 15 | if left < right: 16 | nums[left], nums[right] = nums[right], nums[left] 17 | 18 | 19 | def is_even(num): 20 | return (num & 1) == 0 21 | 22 | if __name__ == '__main__': 23 | tests = [2, 3] 24 | reorder(tests, is_even) 25 | print tests 26 | -------------------------------------------------------------------------------- /third/third/thirteen.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | O(1)时间删除链表结点 4 | 如果有后续结点,后续结点的值前移,删除后续结点,如果没有,只能顺序查找了 5 | """ 6 | 7 | 8 | def delete_node(link, node): 9 | if node == link: # 只有一个结点 10 | del node 11 | if node.next is None: # node是尾结点 12 | while link: 13 | if link.next == node: 14 | link.next = None 15 | link = link.next 16 | else: 17 | node.val = node.next.val 18 | n_node = node.next 19 | node.next = n_node.next 20 | del n_node 21 | 22 | 23 | class ListNode(object): 24 | def __init__(self, x): 25 | self.val = x 26 | self.next = None 27 | 28 | 29 | if __name__ == '__main__': 30 | node1 = ListNode(1) 31 | node1.next = ListNode(2) 32 | node1.next.next = ListNode(3) 33 | delete_node(node1, ListNode(4)) 34 | print node1.val, node1.next.val 35 | 36 | -------------------------------------------------------------------------------- /third/third/twelve.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | 输入n,打印出从1到最大的n位数 4 | Python中已经对大整数可以进行自动转换了,所以不需要考虑大整数溢出问题 5 | """ 6 | 7 | 8 | def print_max_n(n): 9 | for i in xrange(10 ** n): 10 | print i 11 | 12 | 13 | if __name__ == '__main__': 14 | print_max_n(4) 15 | --------------------------------------------------------------------------------