├── __init__.py
├── bit_algorithms
├── __init__.py
└── bit_algorithms.py
├── math_algorithms
├── __init__.py
└── math_algorithms.py
├── other_algorithms
├── __init__.py
└── etc_algorithms.py
├── queue_algorithms
└── __init__.py
├── stack_algorithms
├── __init__.py
└── stack_algorithms.py
├── dynamic_programming
├── __init__.py
├── time_stat.py
├── longest_common_string.py
└── fibonacci_sequence.py
├── linkedlist_algorithms
├── __init__.py
└── linkedlist_algorithms.py
├── searching_algorithms
├── __init__.py
└── searching_algorithms.py
├── sorting_algorithms
├── __init__.py
└── sorting_algorithms.py
├── string_algorithms
├── __init__.py
└── string_algorithms.py
├── .idea
├── misc.xml
├── inspectionProfiles
│ └── profiles_settings.xml
├── modules.xml
├── untitled.iml
└── workspace.xml
└── README.md
/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:45
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/bit_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:36
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/math_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:40
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/other_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:41
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/queue_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:43
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/stack_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:42
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/dynamic_programming/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:34
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/linkedlist_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:40
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/searching_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:37
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/sorting_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:38
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/string_algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:39
4 | # @Author : Cecil Charlie
5 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Data_Structures_and_Algorithms
2 | A range of codes including data structures and algorithms for interviews with Python
3 |
4 | This python package contains much data structures and algorithms questions raised in interviews by famous IT companies in China.
5 | Users could use the solving methods integrated as functions with detailed explanations.
6 | Or, users could browse my blogs in "http://blog.csdn.net/dongrixinyu?ref=toolbar".
7 | More detailed instructions have been provided in there.
8 |
9 |
--------------------------------------------------------------------------------
/.idea/untitled.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/dynamic_programming/time_stat.py:
--------------------------------------------------------------------------------
1 | # -*- coding=utf-8 -*-
2 | # @Time : 20-05-15 下午5:15
3 | # @Author : Cecil Charlie
4 | # ------------------------------------------------------------------------
5 | # 计算耗时的工具
6 |
7 | import time
8 | import typing
9 |
10 |
11 | class TimeStat(object):
12 | def __init__(self, name: str = None):
13 | self.name = name
14 | self.total_time = 0
15 | self.start_time = 0
16 |
17 | def __enter__(self,):
18 | self.start_time = time.time()
19 |
20 | def __exit__(self, *args):
21 |
22 | self.total_time = time.time() - self.start_time
23 | if self.name is not None:
24 | print('`{0:s}` costs {1:.4f} seconds'.format(
25 | self.name. self.total_time))
26 | else:
27 | print('Costs {:.4f} seconds'.format(self.total_time))
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/math_algorithms/math_algorithms.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf-8 -*-
3 |
4 | import math
5 |
6 | class MathAlgorithms(object):
7 | def __init__(self):
8 | pass
9 |
10 | def greatest_common_divisor_1(self, num1, num2):
11 | '''
12 | 数值计算寻找最大公约数,给定两个整数,计算其最大公约数,时间复杂度为 o(min(num1,num2)),取余运算复杂度高
13 | '''
14 | gbc = 1
15 | for i in xrange(2, min(num1, num2)+1):
16 | if num2 % i == 0 and num1 % i == 0:
17 | gbc = i
18 | return gbc
19 |
20 | def greatest_common_divisor_2(self, num1, num2):
21 | '''
22 | 辗转相减法,时间复杂度最差为 o(min(num1,num2)),一般情况下都比这个要好。相减运算要比除法方便很多
23 | '''
24 | while num1 != num2:
25 | if num1 > num2:
26 | num1 = num1 - num2
27 | else:
28 | num2 = num2 - num1
29 | return num1
30 |
31 | def greatest_common_divisor_3(self, num1, num2):
32 | '''
33 | 求余数法,取模运算比较麻烦,时间复杂度低 o(log max(num1, num2))
34 | '''
35 | while num1 != num2:
36 | if num1 > num2:
37 | if num1 % num2 == 0:
38 | return num2
39 | num1 = num1 % num2
40 | else:
41 | if num2 % num1 == 0:
42 | return num1
43 | num2 = num2 % num1
44 | return num1
45 |
46 | def greatest_common_divisor(self, num1, num2):
47 | '''
48 | 求两个数的最大公约数
49 | 综合取余法和辗转相减法,既能得到较好的时间复杂度,又能避免取余运算,时间复杂度稳定 o(log max(num1,num2))
50 | 如果取两个非常大的数的话,前面的方法很容易爆栈、取余困难等等,但是该方法没有问题
51 | a = 999999342353200
52 | b = 777774234
53 | print greatest_common_divisor(a, b)
54 | '''
55 | factor = 1
56 | if num1 < num2:
57 | return greatest_common_divisor_1(num2, num1)
58 | while num1 != num2:
59 | if num1 & 1 is False and num2 & 1 is False: # 均为偶数
60 | num1 = num1 >> 1
61 | num2 = num2 >> 2
62 | factor *= 2
63 | elif num1 & 1 is False and num2 & 1 is True:
64 | num1 = num1 >> 1
65 | elif num1 & 1 is True and num2 & 1 is False:
66 | num2 = num2 >> 1
67 | else:
68 | if num1 > num2:
69 | num1 = num1 - num2
70 | else:
71 | num2 = num2 - num1
72 | return factor*num1
73 |
74 |
75 | a = 454242353200
76 | b = 1400
77 | mathalgorithms = MathAlgorithms()
78 | print mathalgorithms.greatest_common_divisor(a, b)
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/dynamic_programming/longest_common_string.py:
--------------------------------------------------------------------------------
1 | # -*- coding=utf8 -*-
2 | # @Time : 18-1-3 下午2:53
3 | # @Author : Cecil Charlie
4 | # ------------------------------------------------------------------------
5 | '''
6 | 计算两字符串的最长公共子串
7 | ------------------------------------------------------------------------
8 | 字符串1:人工智能在自然语言处理上的应用
9 | 字符串2:自然语言处理的应用非常广泛
10 | 最长公共子串:自然语言处理
11 |
12 | 包括三种方法:
13 | 一、直接计算法,计算复杂度 o(n**3)
14 | 二、采用动态规划的方法保存下已经计算的变量,计算复杂度 o(n**2),空间复杂度 o(len(str1) * len(str2))
15 | 三、删除临时保存的矩阵,节省空间复杂度
16 | '''
17 |
18 | import numpy as np
19 |
20 |
21 | class LongestCommonStringDynamicProgramming(object):
22 | def __init__(self):
23 | pass
24 |
25 | def __call__(self, string_1, string_2, flag=True):
26 | ''' 动态规化法记录比较矩阵,若子串 str1 和 str2 是相同的,
27 | 则 str1[:-1] 和 str2[:-1] 一定是相同的。
28 | '''
29 | length_1 = len(string_1)
30 | length_2 = len(string_2)
31 |
32 | map_matrix = np.zeros((length_1 + 1, length_2 + 1), dtype='int')
33 |
34 | m_max = 0 #最长匹配的长度
35 | position = 0 #最长匹配对应在 s1 中的最后一位
36 | for i in range(length_1):
37 | for j in range(length_2):
38 | # 对其中不必要的比较做删减,加快计算速度
39 | # rule1: 子串在 string_2 上已经不可能再长过当前的最大子串
40 | if flag:
41 | if length_2 - j + map_matrix[i][j] < m_max:
42 | break
43 |
44 | # rule2: 子串在 string_1 上已经不可能再长过当前最大子串
45 | if length_2 - i + map_matrix[i][j] < m_max:
46 | continue
47 |
48 | if string_1[i] == string_2[j]:
49 | map_matrix[i + 1][j + 1] = map_matrix[i][j] + 1
50 | if map_matrix[i + 1][j + 1] > m_max:
51 | m_max = map_matrix[i + 1][j + 1]
52 | position = i + 1
53 | '''
54 | print(' ' + ' '.join(list(string_2)))
55 | for idx, i in enumerate(map_matrix):
56 | if idx == 0:
57 | print(' ', i)
58 | else:
59 | print(string_1[idx - 1], i)
60 | '''
61 | return string_1[position - m_max: position], int(m_max)
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | if __name__ == '__main__':
73 | import time
74 | from time_stat import TimeStat
75 |
76 | lcs_dp = LongestCommonStringDynamicProgramming()
77 | string_1 = '123456778'
78 | string_2 = '129834567486782'
79 | max_iter = 10000
80 |
81 | with TimeStat() as ts:
82 | for i in range(max_iter):
83 | res = lcs_dp(string_1, string_2, flag=False)
84 | with TimeStat() as ts:
85 | for i in range(max_iter):
86 | res = lcs_dp(string_1, string_2, flag=True)
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/other_algorithms/etc_algorithms.py:
--------------------------------------------------------------------------------
1 | # -*- coding=utf-8 -*-
2 |
3 | import random
4 |
5 |
6 | class EightQueensPuzzle(object):
7 | '''
8 | 八皇后问题求解
9 | 代码使用方法:
10 | eight_q = EightQueensPuzzle(4, 5)
11 | print "EIGHT QUEEDS PUZZLE:"
12 | result = eight_q.eight_queens_puzzle()
13 | for i in result:
14 | print i
15 | '''
16 | def __init__(self, n, char):
17 | self.n = n # 棋盘维度
18 | self.char = char # 皇后标记字符
19 |
20 | def init_chess_board(self, n):
21 | '''
22 | 初始化一个棋盘,棋盘规格可以按参数 n 随意选定,一般都讨论八皇后,就选择 8
23 | :return: 返回棋盘,是一个 8*8 矩阵
24 | '''
25 | chess_board = []
26 | for i in xrange(0, n):
27 | line = []
28 | for j in xrange(0, n):
29 | line.append(0)
30 | chess_board.append(line)
31 | return chess_board
32 |
33 | def update_conflict_board(self, conflict_board, position):
34 | for k in xrange(0, self.n): # 为行添加 1
35 | conflict_board[position[0]][k] = 1
36 | for id in xrange(position[0]+1, self.n):
37 | conflict_board[id][position[1]] = 1 # 为列添加 1
38 | if position[0] + position[1] - id >= 0: # 为左斜添加 1
39 | conflict_board[id][position[0] + position[1] - id] = 1
40 | if position[1] - position[0] + id < self.n: # 为右斜添加 1
41 | conflict_board[id][position[1] - position[0] + id] = 1
42 |
43 | def queens_conflict(self, conflict_board, position):
44 | '''
45 | 当前棋盘的状态是 conflict_board, 判定如果在 position 位置给一个皇后的话,会不会出现问题。
46 | 如果有问题则返回 False,如果没有问题返回 True
47 | '''
48 | if conflict_board[position[0]][position[1]] != 0:
49 | return False
50 | else:
51 | return True
52 |
53 | def eight_queens_puzzle(self):
54 | '''
55 | 给出一个八皇后的求解答案。
56 | :return:返回一个结果并打印.
57 | '''
58 | import random
59 | while True: # 不停寻找符合条件的八皇后排列
60 | chess_board = self.init_chess_board(self.n)
61 | conflict_board = self.init_chess_board(self.n)
62 | for i in xrange(0, self.n):
63 | flag = 0
64 | for cnt in conflict_board[i]:
65 | if cnt != 0:
66 | flag += 1
67 | if flag == self.n: # 如果已经1被填满了,说明这个答案错误
68 | break
69 |
70 | while True:
71 | pos = [i, random.randint(0, self.n-1)] # 元组构成皇后的位置
72 | if self.queens_conflict(conflict_board, pos): # 如果没有冲突
73 | chess_board[i][pos[1]] = self.char
74 | self.update_conflict_board(conflict_board, pos)
75 | break
76 | if self.char in chess_board[self.n-1]:
77 | return chess_board
78 |
79 |
--------------------------------------------------------------------------------
/bit_algorithms/bit_algorithms.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python2.7
2 | # -*- coding=utf8 -*-
3 | # @Time : 18-1-3 下午8:35
4 | # @Author : Cecil Charlie
5 |
6 |
7 | class BitAlgorithms(object):
8 | '''
9 | 位运算算法合集
10 | '''
11 |
12 | def __init__(self):
13 | pass
14 |
15 | def exchage_nums(self, a, b):
16 | '''
17 | 不用额外变量交换两个整数值,空间节省了,时间负责度略高一些。
18 | '''
19 | a = a ^ b
20 | b = a ^ b
21 | a = a ^ b
22 | return a, b
23 |
24 | def add_bit(self, a, b):
25 | '''
26 | 位运算实现两个整数相加,python里只能针对正数来处理
27 | '''
28 | sum = a
29 | while b != 0:
30 | sum = a ^ b
31 | b = (a & b) << 1
32 | a = sum
33 | return sum
34 |
35 | def count1(self, a):
36 | '''
37 | 整数的二进制表达里有多少个1,复杂度为a的二进制长度。
38 | '''
39 | num = 0
40 | while a != 0:
41 | num += a & 1
42 | a >>= 1
43 | return num
44 |
45 | def count2(self, a):
46 | '''
47 | 整数的二进制表达里有多少个1,复杂度仅为1的个数
48 | '''
49 | num = 0
50 | while a != 0:
51 | a = a & (a - 1)
52 | num += 1
53 | return num
54 |
55 | def print_odd_times_num1(self, arr):
56 | '''
57 | 给定一个数组,数据都是整数,其中只有一个数字出现了奇数次,其它都是偶数次。找出那个奇数次的数字。
58 | 时间复杂度o(n),空间复杂度为o(1)。
59 | 整数 n 与 0 的异或结果为 n。整数 n 与 n的异或结果为0,异或运算满足交换律和结合律
60 | '''
61 | odd = 0
62 | for i in arr:
63 | odd ^= i
64 | return odd
65 |
66 | def print_odd_times_num2(self, arr):
67 | '''
68 | 给定一个数组,数据都是整数,其中只有2个数字出现了奇数次,其它都是偶数次。找出那2个奇数次的数字。
69 | 时间复杂度o(n),空间复杂度为o(1)。
70 | 如果有两个数字出现了奇数次,比如是 a 和 b,则最终 odd 结果为 a^b,但其中一定有差别。
71 | '''
72 | odd, odd_one = 0, 0
73 | for i in arr:
74 | odd ^= i
75 | right = odd & (~odd + 1) # odd的第k位是1,即两个奇数个的数字的第k位一定不同
76 | for i in arr:
77 | if i & right != 0:
78 | odd_one ^= i
79 | return odd_one, odd_one ^ odd
80 |
81 | def get_num_from_k_arr(self, arr, k):
82 | '''
83 | 在其它数都出现 k 次的数组中找到只出现一次的数。k 大于 1。
84 | 数组 arr 中,只有一个数出现了 1 次,其它都出现了 k 次,找出那个出现1次的数。
85 | 时间复杂度 o(n),额外空间复杂度为 o(1)
86 | 解法是:如果两个 k 进制数 a,b无进位相加,其结果一定是 (a(i)+b(i))%k,如果是 k 个 k进制数相加,其结果一定是 k 个 0
87 | '''
88 | e0 = 0
89 | for i in arr:
90 | e0 = (e0 + i) % k # 错误的,有两个问题需要克服,k进制数如何处理,无进位相加如何处理。
91 | return e0
92 |
93 |
94 | bit = BitAlgorithms()
95 | print bit.add_bit(543, 240)
96 | print bit.count1(329)
97 | print bit.count2(329)
98 | print bit.print_odd_times_num1([3, 4, 1, 9, 55, 55, 4, 1, 9])
99 | print bit.print_odd_times_num2([3, 4, 1, 9, 55, 55, 3, 82, 1, 9])
100 | print bit.get_num_from_k_arr([3, 4, 4, 1, 1, 9, 55, 9, 55, 55, 4, 1, 9],3)
--------------------------------------------------------------------------------
/dynamic_programming/fibonacci_sequence.py:
--------------------------------------------------------------------------------
1 | # -*- coding=utf8 -*-
2 | # @Time : 18-1-3 下午2:53
3 | # @Author : Cecil Charlie
4 | # ------------------------------------------------------------------------
5 | '''
6 | 计算斐波那契数列
7 | ------------------------------------------------------------------------
8 | 斐波那契数列:
9 | 0 1 2 3 4 5 6 7 8
10 | 0 1 1 2 3 5 8 13 21
11 |
12 | 包括三种方法:
13 | 一、数列公式计算,即递归计算法,计算复杂度 o(2**n),
14 | 二、考虑到重复计算,采用循环的方式,每次保存了前一步的计算结果,速度大大加快,计算复杂度 o(n)
15 | 三、考虑采用矩阵运算,进一步利用较大的空间,使得速度上有加快,计算复杂度 o(log n)。
16 | '''
17 |
18 | import os
19 | import sys
20 | import copy
21 |
22 | import numpy as np
23 |
24 |
25 | __all__ = ['FibonacciRecursion', 'FibonacciIteration',
26 | 'FibonacciMatrix']
27 |
28 |
29 | class FibonacciRecursion(object):
30 | '''
31 | 数列公式计算,即递归计算法,计算复杂度 o(2**n),
32 | '''
33 | def __init__(self):
34 | # 用于指定最大迭代次数
35 | self.n = -1
36 |
37 | def __call__(self, n):
38 | '''
39 | :param n: 数列的第n个索引
40 | :return: 索引n对应的值
41 | '''
42 | # 配置相应的最大迭代次数
43 | if n < 0:
44 | return None
45 |
46 | if self.n < n and n > 1000:
47 | sys.setrecursionlimit(n)
48 | self.n = n
49 |
50 | if n < 1:
51 | return 0
52 |
53 | if n == 1 or n == 2:
54 | return 1
55 |
56 | return self.__call__(n-1) + self.__call__(n-2)
57 |
58 |
59 | class FibonacciIteration(object):
60 | '''
61 | 采用循环迭代的方式计算,每次保存了前一步的计算结果,速度大大加快,计算复杂度 o(n)
62 | '''
63 | def __init__(self):
64 | pass
65 |
66 | def __call__(self, n):
67 | """
68 | 用循环替代递归,空间复杂度急剧降低,时间复杂度为o(n)
69 | """
70 | if n < 1:
71 | return 0
72 |
73 | if n == 1 or n == 2:
74 | return 1
75 |
76 | res = 1
77 | tmp1 = 0
78 | tmp2 = 1
79 | for _ in range(1, n):
80 | res = tmp1 + tmp2
81 | tmp1 = tmp2
82 | tmp2 = res
83 | return res
84 |
85 |
86 | class FibonacciMatrix(object):
87 | '''
88 | 考虑采用矩阵运算,进一步利用较大的空间,使得速度上有加快,计算复杂度 o(log n)。
89 | 当然了,这种方法需要额外计算矩阵,计算矩阵的时间开销没有算在内.其中还运用到了位运算。
90 | '''
91 | def __init__(self):
92 | pass
93 |
94 | def __call__(self, n):
95 | base = [[1, 1], [1, 0]]
96 | if n < 1:
97 | return 0
98 | if n == 1 or n == 2:
99 | return 1
100 | res = self.__matrix_power(base, n-2)
101 | return res[0][0] + res[1][0]
102 |
103 | def __matrix_power(self, mat, n):
104 | """
105 | 求一个方阵的幂,时间复杂度为 o(log n)
106 | """
107 | if len(mat) != len(mat[0]):
108 | raise ValueError("The mat is not a square array.")
109 |
110 | if n < 0 or type(n) is not int:
111 | raise ValueError("The power is unsuitable.")
112 |
113 | product = np.identity(len(mat))
114 | tmp = mat
115 | while n > 0:
116 | if (n & 1) != 0:
117 | # 按位与的操作,在幂数的二进制位为1时,
118 | # 乘到最终结果上,否则自乘
119 | product = self._multiply_matrix(product, tmp)
120 | tmp = self._multiply_matrix(tmp, tmp)
121 | n >>= 1
122 |
123 | return product
124 |
125 | @staticmethod
126 | def _multiply_matrix(mat1, mat2):
127 | """
128 | 矩阵乘法
129 | :param m: 矩阵1,二维列表
130 | :param n: 矩阵2
131 | :return: numpy 格式的矩阵
132 | """
133 | if len(mat1[0]) != len(mat2):
134 | raise ValueError('The dimention of matrix1 and matrix2 is not same')
135 |
136 | product = np.zeros((len(mat1), len(mat2[0])))
137 | for i in range(0, len(mat1)):
138 | for j in range(0, len(mat2[0])):
139 | for k in range(0, len(mat1[0])):
140 | if mat1[i][k] != 0 and mat2[k][j] != 0:
141 | product[i][j] += mat1[i][k] * mat2[k][j]
142 | return product
143 |
144 |
145 | if __name__ == '__main__':
146 | fib_rec = FibonacciRecursion()
147 | fib_iter = FibonacciIteration()
148 | fib_mat = FibonacciMatrix()
149 | n = 180
150 | max_iter = 1000
151 | import time
152 | start_time = time.time()
153 | for i in range(max_iter):
154 | fib_rec(n)
155 | print(time.time() - start_time)
156 |
157 | start_time = time.time()
158 | for i in range(max_iter):
159 | fib_iter(n)
160 | print(time.time() - start_time)
161 |
162 | start_time = time.time()
163 | for i in range(max_iter):
164 | fib_mat(n)
165 | print(time.time() - start_time)
166 |
167 |
168 |
--------------------------------------------------------------------------------
/stack_algorithms/stack_algorithms.py:
--------------------------------------------------------------------------------
1 | # -*- coding=utf-8 -*-
2 |
3 |
4 | class Node(object):
5 | # 栈结点
6 | def __init__(self, value, next=0):
7 | self.value = value
8 | self.next = next # 指针
9 |
10 |
11 | class Stack(object):
12 | # 由于 Python 难以对内存地址进行操作,所以这里给出了链栈的数据结构
13 | # 由于栈的操作比线性表少很多,所以顺序栈的表示法要比链栈方便快捷
14 | def __init__(self):
15 | self.head = 0
16 |
17 | def init_stack(self, data):
18 | self.head = Node(data[0])
19 | p = self.head
20 | for i in data[1:]:
21 | p.next = Node(i)
22 | p = p.next
23 |
24 | def clear_stack(self):
25 | self.head = 0
26 |
27 | def is_empty(self):
28 | if self.head == 0:
29 | return True
30 | else:
31 | return False
32 |
33 | def get_length(self):
34 | p, length = self.head, 0
35 | while p != 0:
36 | length += 1
37 | p = p.next
38 | return length
39 |
40 | def push(self, value): # 向栈中添加一个结点
41 | if self.is_empty():
42 | self.head = Node(value)
43 | else:
44 | p = self.head
45 | for _ in xrange(self.get_length() - 1):
46 | p = p.next
47 | p.next = Node(value)
48 |
49 | def get_top(self): # 获得栈顶元素
50 | if self.is_empty():
51 | print 'This is an empty stack.'
52 | return
53 | else:
54 | p = self.head
55 | for _ in xrange(self.get_length()):
56 | p = p.next
57 | return p.value
58 |
59 | def pop(self): # 弹出栈顶元素
60 | length = self.get_length()
61 | if self.is_empty():
62 | print 'This is an empty stack.'
63 | return
64 | elif length == 1:
65 | p = self.head
66 | self.head = 0
67 | return p.value
68 | elif length == 2:
69 | p = self.head
70 | value = p.next.value
71 | self.head.next = 0
72 | return value
73 | else:
74 | p = self.head
75 | for _ in xrange(1, length - 1):
76 | p = p.next
77 | pop = p.next
78 | p.next = 0
79 | return pop.value
80 |
81 | def show_stack(self): # 打印栈中的所有元素
82 | if self.is_empty():
83 | print 'This is an empty stack.'
84 | else:
85 | p, container = self.head, []
86 | for _ in xrange(self.get_length() - 1):
87 | container.append(p.value)
88 | p = p.next
89 | container.append(p.value)
90 | print container
91 |
92 | def get_min(self):
93 | '''
94 | 返回链栈中的最小的元素的值,要求时间复杂度为 o(1),主要方法是用空间换时间,构建一个存放最小栈元素的栈 stackmin。
95 | 每次向栈中添加元素的时候,都判断这个元素是不是比栈中的元素小,如果是相等或更小,则将该数放在 stackmin 中。
96 | 每次弹出一个栈顶元素,判断该数是不是比 stackmin的栈顶元素大,如果大,则 stackmin不需要任何操作。
97 | 在查询时,直接返回stackmin的栈顶元素即可。
98 | '''
99 | self.stackmin.pop()
100 |
101 |
102 | s = Stack()
103 | s.init_stack([1])
104 | print s.get_length()
105 | s.show_stack()
106 | # print "top node: ", s.get_top()
107 | s.push(999)
108 | s.show_stack()
109 | print "pop: ", s.pop()
110 | s.show_stack()
111 |
112 |
113 | class StackAlgorithms(object):
114 | def __init__(self):
115 | pass
116 |
117 |
118 |
119 | class SpecialStack(object):
120 | def __init__(self):
121 | self.head = 0
122 | self.stackmin = []
123 |
124 | def init_stack(self, data):
125 | self.head = Node(data[0])
126 | if self.stackmin =[]:
127 | self.stackmin.append(data[0])
128 | p = self.head
129 | for i in data[1:]:
130 | p.next = Node(i)
131 | pop = self.stackmin.pop()
132 | if pop >= i:
133 | self.stackmin.append(pop)
134 | self.stackmin.append(i)
135 | else:
136 | self.stackmin.append(pop)
137 | p = p.next
138 |
139 | def clear_stack(self):
140 | self.head = 0
141 | self.stackmin = []
142 |
143 | def is_empty(self):
144 | if self.head == 0:
145 | return True
146 | else:
147 | return False
148 |
149 | def get_length(self):
150 | p, length = self.head, 0
151 | while p != 0:
152 | length += 1
153 | p = p.next
154 | return length
155 |
156 | def push(self, value): # 向栈中添加一个结点
157 | if self.is_empty():
158 | self.head = Node(value)
159 | else:
160 | p = self.head
161 | for _ in xrange(self.get_length() - 1):
162 | p = p.next
163 | p.next = Node(value)
164 | pop = self.stackmin.pop()
165 | if pop >= value:
166 | self.stackmin.append(pop)
167 | self.stackmin.append(value)
168 | else:
169 | self.stackmin.append(pop)
170 |
171 | def get_top(self): # 获得栈顶元素
172 | if self.is_empty():
173 | print 'This is an empty stack.'
174 | return
175 | else:
176 | p = self.head
177 | for _ in xrange(self.get_length()):
178 | p = p.next
179 | return p.value
180 |
181 | def pop(self): # 弹出栈顶元素
182 | length = self.get_length()
183 | if self.is_empty():
184 | print 'This is an empty stack.'
185 | return
186 | elif length == 1:
187 | p = self.head
188 | self.head = 0
189 | self.stackmin = []
190 | return p.value
191 | elif length == 2:
192 | p = self.head
193 | value = p.next.value
194 | self.head.next = 0
195 | if len(self.stackmin) == 2:
196 | self.stackmin.pop()
197 | return value
198 | else:
199 | p = self.head
200 | for _ in xrange(1, length - 1):
201 | p = p.next
202 | pop = p.next
203 | p.next = 0
204 | stack_min = self.stackmin.pop()
205 | if stack_min < pop.value:
206 | self.stackmin.append(stack_min)
207 | return pop.value
208 |
209 | def show_stack(self): # 打印栈中的所有元素
210 | if self.is_empty():
211 | print 'This is an empty stack.'
212 | else:
213 | p, container = self.head, []
214 | for _ in xrange(self.get_length() - 1):
215 | container.append(p.value)
216 | p = p.next
217 | container.append(p.value)
218 | print container
219 |
220 | def get_min(self):
221 | '''
222 | 返回链栈中的最小的元素的值,要求时间复杂度为 o(1),主要方法是用空间换时间,构建一个存放最小栈元素的栈 stackmin。
223 | 每次向栈中添加元素的时候,都判断这个元素是不是比栈中的元素小,如果是相等或更小,则将该数放在 stackmin 中。
224 | 每次弹出一个栈顶元素,判断该数是不是比 stackmin的栈顶元素大,如果大,则 stackmin不需要任何操作。
225 | 在查询时,直接返回stackmin的栈顶元素即可。
226 | '''
227 | pop = self.stackmin.pop()
228 | self.stackmin.append(pop)
229 | return pop
230 |
--------------------------------------------------------------------------------
/searching_algorithms/searching_algorithms.py:
--------------------------------------------------------------------------------
1 | # -*- coding=utf-8 -*-
2 |
3 | # from sorting_algorithms import SortingAlgorithms
4 |
5 |
6 | class SearchingAlgorithms(object):
7 | '''
8 | 七大查找算法 Python 版,所有待查序列里都是按主键来查找,即没有主键相同的两项。
9 | 所有的查找算法的空间复杂度都比较低,因为比较之后无需存储比较结果,也无需存储被比较的值。
10 | 时间复杂度根据被查找的值波动变化非常大,所以使用平均查找长度 ASL 来衡量算法性能。
11 |
12 | 静态查找主要包括:顺序查找,折半二分查找,斐波那契查找,插值查找
13 | 树查找主要包括:次优查找树,二叉查找树,平衡二叉树,2-3树,红黑树,b树,b+树,键树
14 |
15 | 按照分块思想的查找有:索引顺序查找,键值查找
16 |
17 |
18 | '''
19 |
20 | def __init__(self):
21 | pass
22 |
23 | def sequential_search(self, lists, key):
24 | '''
25 | 顺序查找算法,最简单的一种,静态查找,等概分布,针对没有排序的序列而言。平均查找长度 ASL = (n+1)/2
26 | 设立哨兵的方法,避免每次都检测是否检测完整个表,本函数没写哨兵。
27 | :param lists: 待查链表,顺序表等等。
28 | :param key: 待查关键字
29 | :return: 如果查到了,返回索引位置,如果没有查到,返回 -1
30 | '''
31 | for i in xrange(0, len(lists)):
32 | if lists[i] == key:
33 | return i
34 | return -1
35 |
36 | def binary_search(self, lists, key):
37 | '''
38 | 二分查找法,又叫折半查找,应用于等概分布的有序序列,利用了判定树,平均查找长度 ASL = (log2 n+1) - 1
39 | '''
40 | if lists == []:
41 | return -1
42 | if len(lists) == 1:
43 | if key == lists[0]:
44 | return 0
45 | else:
46 | return -1
47 | lists = sorted(lists) # 先排序
48 | print lists # [-6, 2, 3, 4, 9, 10, 13, 47, 78, 90, 111, 125, 345, 908, 999]
49 | low, high = 0, len(lists) - 1
50 | while low < high:
51 | mid = (low + high) / 2
52 | if lists[mid] > key:
53 | high = mid - 1
54 | if lists[mid] < key:
55 | low = mid + 1
56 | if lists[mid] == key:
57 | return mid
58 | return -1
59 |
60 | def insertion_search(self, lists, key):
61 | '''
62 | 插值查找,二分折半查找的改进型,应用于等概分布,其实计算 mid 值消耗的时间也比较多,因为有很多乘除法运算。
63 | 适用于有序的,均匀分布的,非常大数据量的查找。
64 | '''
65 | if lists == []:
66 | return -1
67 | if len(lists) == 1:
68 | if key == lists[0]:
69 | return 0
70 | else:
71 | return -1
72 | lists = sorted(lists) # 先排序
73 | low, high = 0, len(lists) - 1
74 | while low < high:
75 | if key - lists[low] < 0: # 以免出现回退
76 | return -1
77 | mid = low + (key - lists[low]) / (lists[high] - lists[low]) * (high - low)
78 | if lists[mid] > key:
79 | high = mid - 1
80 | if lists[mid] < key:
81 | low = mid + 1
82 | if lists[mid] == key:
83 | return mid
84 | return -1
85 |
86 | def fibonacci_search(self, lists, key):
87 | '''
88 | 斐波那契查找算法,插值查找的一种,针对有序静态查找表来做。整体性能优于折半查找,但是在最坏情况下,比折半查找要差。
89 | 相较于插值查找,不需要做乘除法运算,应用于等概分布
90 | '''
91 | if lists == []:
92 | return -1
93 | if len(lists) == 1:
94 | if key == lists[0]:
95 | return 0
96 | else:
97 | return -1
98 | lists = sorted(lists) # 先排序
99 |
100 | # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34,...]
101 | def fibonacci(n):
102 | if n == 0:
103 | return 0
104 | if n == 1:
105 | return 1
106 | f = [0]
107 | f.append(1)
108 | for i in xrange(2, n + 1):
109 | f.append(f[i - 1] + f[i - 2])
110 | return f.pop()
111 |
112 | low, high = 0, len(lists)-1
113 | i = 1
114 | while fibonacci(i) < len(lists):
115 | i += 1
116 | if key == lists[high]+1:
117 | return -1
118 | for _ in xrange(len(lists), fibonacci(i)):
119 | lists.append(lists[high]+1)
120 | high = len(lists) - 1
121 | #print "fibonacci: ", i, high, fibonacci(i)
122 | while low <= high:
123 | mid = fibonacci(i-1) + low
124 | if lists[mid] == key:
125 | return mid
126 | if lists[mid] < key:
127 | low = mid + 1
128 | i -= 2
129 | if lists[mid] > key:
130 | high = mid - 1
131 | i -= 1
132 | return -1
133 |
134 | def binary_search_tree_search(self, lists, key):
135 | '''
136 | 二叉查找树,又称为二叉排序树,对于每一个节点,其左子节点一定比其小,右子节点一定比其大。一般采用二叉链表作为存储结构。
137 | 由于构建 BST 的过程是个动态的过程,所以二叉查找树是一个动态查找表的查找。
138 | 二叉树如果中序遍历,其结果就是有序数组。
139 | 平均查找长度是 2(1+ 1/n)(ln n), 时间复杂度为 o(log2 n),在最坏情况下,是 o(n),此时需要平衡化处理。
140 | 一、每次添加一个结点,一定是在 BST的叶子节点上,每次插入都只需修改某个叶子节点的指针即可。
141 | 二、每次删除一个结点,
142 | 1、若是叶子节点,由于其没有子树,所以只需修改其父节点的指针即可。
143 | 2、若是只有左子树或者右子树,则分情况讨论,若该结点是其双亲结点的左子树结点,则让这颗子树成为其父节点的左子树;
144 | 若该结点是其双亲结点的右子树结点,则让这颗子树成为其父结点的右子树。
145 | 3、若是左右子树都存在,则有两种处理方法,具体需要看图和代码来理解。
146 | '''
147 |
148 | def balanced_binary_tree_search(self, lists, key):
149 | '''
150 | 平衡二叉树,又叫 AVL 树,左右子树都是平衡二叉树,且左右子树的深度之差不超过 1。
151 | 由于二叉查找树性能恶化的原因在于树趋近于链表,也就是左右不平衡,所以平衡二叉树能够改善 BST的不稳定性能。
152 | 其平均查找时间同样是 o(log2 n),且效果比 BST 稳定。
153 | 将二叉排序树改造成平衡二叉树的方法,也就是插入和删除的时候保持平衡,较为复杂,书本上有就不细说了。
154 |
155 | 平衡二叉树分为 平衡2-3树和平衡红黑树,效率都比较高,但是真复杂啊。红黑树是 2-3树的一种简单实现。
156 |
157 | 平衡2-3树:
158 | "2-3查找树定义":和二叉树不一样,2-3树运行每个节点保存1个或者两个的值。对于普通的2节点(2-node),他保存1个key和左右两个自己点。
159 | 对应3节点(3-node),保存两个Key,2-3查找树的定义如下:
160 | 1)要么为空,要么:
161 | 2)对于2节点,该节点保存一个key及对应value,以及两个指向左右节点的节点,左节点也是一个2-3节点,所有的值都比key要小,右节点也
162 | 是一个2-3节点,所有的值比key要大。
163 | 3)对于3节点,该节点保存两个key及对应value,以及三个指向左中右的节点。左节点也是一个2-3节点,所有的值均比两个key中的最小的
164 | key还要小;中间节点也是一个2-3节点,中间节点的key值在两个跟节点key值之间;右节点也是一个2-3节点,节点的所有key值比两个
165 | key中的最大的key还要大。
166 |
167 | "2-3查找树的性质":
168 | 1)如果中序遍历2-3查找树,就可以得到排好序的序列;
169 | 2)在一个完全平衡的2-3查找树中,根节点到每一个为空节点的距离都相同。(这也是平衡树中“平衡”一词的概念,根节点到叶节点的最长距离
170 | 对应于查找算法的最坏情况,而平衡树中根节点到叶节点的距离都一样,最坏情况也具有对数复杂度。
171 |
172 | 平衡红黑树:
173 | 2-3查找树能保证在插入元素之后能保持树的平衡状态,最坏情况下即所有的子节点都是2-node,树的高度为lgn,从而保证了最坏情况下的时
174 | 间复杂度。但是2-3树实现起来比较复杂,于是就有了一种简单实现2-3树的数据结构,即红黑树(Red-Black Tree)。
175 |
176 | 基本思想:红黑树的思想就是对2-3查找树进行编码,尤其是对2-3查找树中的3-nodes节点添加额外的信息。红黑树中将节点之间的链接分为
177 | 两种不同类型,红色链接,他用来链接两个2-nodes节点来表示一个3-nodes节点。黑色链接用来链接普通的2-3节点。特别的,使用红色链接的两个
178 | 2-nodes来表示一个3-nodes节点,并且向左倾斜,即一个2-node是另一个2-node的左子节点。这种做法的好处是查找的时候不用做任何修改,和
179 | 普通的二叉查找树相同。
180 |
181 | “红黑树的定义”:红黑树是一种具有红色和黑色链接的平衡查找树,同时满足:
182 | 1、红色节点向左倾斜
183 | 2、一个节点不可能有两个红色链接
184 | 3、整个树完全黑色平衡,即从根节点到所以叶子结点的路径上,黑色链接的个数都相同。
185 | 下图可以看到红黑树其实是2-3树的另外一种表现形式:如果我们将红色的连线水平绘制,那么他链接的两个2-node节点就是2-3树中的一个
186 | 3-node节点了。
187 |
188 | “红黑树的性质”:整个树完全黑色平衡,即从根节点到所以叶子结点的路径上,黑色链接的个数都相同(2-3树的第2)性质,从根节点到叶子节
189 | 点的距离都相等)。
190 | “复杂度分析”:最坏的情况就是,红黑树中除了最左侧路径全部是由3-node节点组成,即红黑相间的路径长度是全黑路径长度的2倍。
191 |
192 |
193 | '''
194 |
195 | def b_tree_search(self,lists, key):
196 | '''
197 | B树查找:B树(B-tree)是一种树状数据结构,它能够存储数据、对其进行排序并允许以O(log n)的时间复杂度运行进行查找、顺序读取、插入和\
198 | 删除的数据结构。B树,概括来说是一个节点可以拥有多于2个子节点的二叉查找树。与自平衡二叉查找树不同,B树为系统最优化大块数据的读和写操作。\
199 | B-tree算法减少定位记录时所经历的中间过程,从而加快存取速度。普遍运用在数据库和文件系统。
200 | “B树定义”:
201 | B树可以看作是对 2-3查找树的一种扩展,即他允许每个节点有 M-1个子节点。根节点至少有两个子节点,每个节点有 M-1个key,并且以升序排\
202 | 列,位于 M-1和 M key的子节点的值位于 M-1 和 M key对应的 Value之间,其它节点至少有 M/2个子节点。
203 |
204 | B+树定义:
205 | B+树是对B树的一种变形树,它与B树的差异在于:
206 | 1、有k个子结点的结点必然有k个关键码;
207 | 2、非叶结点仅具有索引作用,跟记录有关的信息均存放在叶结点中。
208 | 3、树的所有叶结点构成一个有序链表,可以按照关键码排序的次序遍历全部记录。
209 |
210 | B和 B+树的区别在于,B+树的非叶子结点只包含导航信息,不包含实际的值,所有的叶子结点和相连的节点使用链表相连,便于区间查找和遍历。
211 |
212 | B+ 树的优点在于:
213 | 由于B+树在内部节点上不好含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子几点上\
214 | 关联的数据也具有更好的缓存命中率。B+树的叶子结点都是相链的,因此对整棵树的便利只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,\
215 | 所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。相邻的元素可能在内存中不相邻,所以缓存命中性没有B+树好。
216 | 但是B树也有优点,其优点在于,由于B树的每一个节点都包含key和value,因此经常访问的元素可能离根节点更近,因此访问也更迅速。
217 |
218 | B/B+树常用于文件系统和数据库系统中,它通过对每个节点存储个数的扩展,使得对连续的数据能够进行较快的定位和访问,能够有效减少查找时\
219 | 间,提高存储的空间局部性从而减少IO操作。它广泛用于文件系统及数据库中,如:
220 | Windows:HPFS文件系统;
221 | Mac:HFS,HFS+文件系统;
222 | Linux:ResiserFS,XFS,Ext3FS,JFS文件系统;
223 | 数据库:ORACLE,MYSQL,SQLSERVER等中。
224 | '''
225 |
226 | def digital_search_tree_search(self, lists, key):
227 | '''
228 | 键树,又称数字查找树,利用的基本思想类似于我们查英文字典。也就是把序列中的关键字拆分成若干部分,这些部分可作为每一层键树种的结点。\
229 | 组合起来之后即可得到要查询的关键字,最典型的应用也是查找英文单词。事先将所有的英文单词组织成一颗键树,达到效率最高。
230 | 键树的存储结构:
231 | 1、多重链表,最容易想到的存储结构;
232 | 2、孩子兄弟链表来表示键树,左子节点是孩子,右子节点是兄弟。两种表示方法即普通树和二叉树之间的互换。
233 | '''
234 |
235 | def hash_search(self, lists, key):
236 | '''
237 | 什么是哈希表(Hash)?
238 | 我们使用一个下标范围比较大的数组来存储元素。可以设计一个函数(哈希函数, 也叫做散列函数),使得每个元素的关键字都与一个函数值(即数\
239 | 组下标)相对应,于是用这个数组单元来存储这个元素;也可以简单的理解为,按照关键字为每一个元素"分类",然后将这个元素存储在相应"类"所对应的地\
240 | 方。但是,不能够保证每个元素的关键字与函数值是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了"冲突",换句话\
241 | 说,就是把不同的元素分在了相同的"类"之中。后面我们将看到一种解决"冲突"的简便做法。
242 | 总的来说,"直接定址"与"解决冲突"是哈希表的两大特点。
243 |
244 | 什么是哈希函数?
245 | 哈希函数的规则是:通过某种转换关系,使关键字适度的分散到指定大小的的顺序结构中,越分散,则以后查找的时间复杂度越小,空间复杂度越高。
246 | 算法思想:哈希的思路很简单,如果所有的键都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索引,值即为其对应的值,这样就可\
247 | 以快速访问任意键的值。这是对于简单的键的情况,我们将其扩展到可以处理更加复杂的类型的键。
248 |
249 | 算法流程:
250 | 1)用给定的哈希函数构造哈希表;
251 | 2)根据选择的冲突处理方法解决地址冲突;
252 | 常见的解决冲突的方法:拉链法和线性探测法。
253 | 3)在哈希表的基础上执行哈希查找。
254 | 哈希表是一个在时间和空间上做出权衡的经典例子。如果没有内存限制,那么可以直接将键作为数组的索引。那么所有的查找时间复杂度为O(1);如\
255 | 果没有时间限制,那么我们可以使用无序数组并进行顺序查找,这样只需要很少的内存。哈希表使用了适度的时间和空间来在这两个极端之间找到了平衡。只需\
256 | 要调整哈希函数算法即可在时间和空间上做出取舍。
257 |
258 | 复杂度分析:
259 | 单纯论查找复杂度:对于无冲突的Hash表而言,查找复杂度为O(1)(注意,在查找之前我们需要构建相应的Hash表)。
260 |
261 | 使用Hash,我们付出了什么?
262 | 我们在实际编程中存储一个大规模的数据,最先想到的存储结构可能就是map,也就是我们常说的KV pair,经常使用Python的博友可能更有这种体\
263 | 会。使用map的好处就是,我们在后续处理数据处理时,可以根据数据的key快速的查找到对应的value值。map的本质就是Hash表,那我们在获取了超高查找\
264 | 效率的基础上,我们付出了什么?
265 |
266 | Hash是一种典型以空间换时间的算法,比如原来一个长度为100的数组,对其查找,只需要遍历且匹配相应记录即可,从空间复杂度上来看,假如数\
267 | 组存储的是byte类型数据,那么该数组占用100byte空间。现在我们采用Hash算法,我们前面说的Hash必须有一个规则,约束键与存储位置的关系,那么就需\
268 | 要一个固定长度的hash表,此时,仍然是100byte的数组,假设我们需要的100byte用来记录键与位置的关系,那么总的空间为200byte,而且用于记录规则\
269 | 的表大小会根据规则,大小可能是不定的。
270 | '''
271 |
272 | search = SearchingAlgorithms()
273 | l = [4, 90, 125, 2, 9, 47, 999, -6, 111, 908, 13, 78, 345, 3, 10,909]
274 | print "Sequential search: ", search.sequential_search(l, 10)
275 | print "Binary search: ", search.binary_search([101], 101)
276 | print "Insertion search: ", search.insertion_search(l, 907)
277 | print "Fibonacci search: ", search.fibonacci_search(l, 4)
278 | print search.b_tree_search.__doc__
279 |
--------------------------------------------------------------------------------
/sorting_algorithms/sorting_algorithms.py:
--------------------------------------------------------------------------------
1 | # -*- coding=utf-8 -*-
2 |
3 | import time
4 | import random
5 | import unittest
6 |
7 |
8 | def timeCount(func): # 装饰器计算时间
9 | def wrapper(*arg,**kwarg):
10 | start = time.clock()
11 | func(*arg,**kwarg)
12 | end =time.clock()
13 | print 'used:', end - start
14 | return wrapper
15 |
16 |
17 | class Executor:
18 | def __init__(self, func, *args, **kwargs):
19 | self.func = func
20 | self.args = args
21 | self.kwargs = kwargs
22 | self.do()
23 |
24 | @timeCount
25 | def do(self):
26 | print '-----start:',self.func,'-----'
27 | self.ret = self.func(*self.args, **self.kwargs)
28 |
29 | def __del__(self):
30 | print '-----end-----'
31 |
32 |
33 | class TestSort(unittest.TestCase): # 测试类的使用
34 |
35 | def test_01_bubbleSort(self):
36 | Executor(SortingAlgorithms().bubble_sort, L[:])
37 |
38 | def test_11_builtinSort(self):
39 | Executor(sorted, L[:])
40 |
41 |
42 | class SortingAlgorithms(object):
43 | '''
44 | 冒泡法:对比模型,原数组上排序,稳定,慢
45 | 插入法:对比模型,原数组上排序,稳定,慢
46 | 选择法:对比模型,原数组上排序,稳定,慢
47 | 归并法:对比模型,非原数组上排序,稳定,快
48 | 快速法:对比模型,原数组上排序,不稳定,快
49 | 堆排序:对比模型,原数组上排序,不稳定,快,空间复杂度为1个辅助空间
50 | 二叉树排序:对比模型,非数组上排序,不稳定,快
51 | 桶排序:非对比模型,非原数组上排序,不稳定,快
52 | 基数排序:非对比模型,非原数组上排序,稳定,快
53 | 基于比较模型的排序算法的复杂度最高可以做到 o(n*log2 n),这是二叉树形比较结构决定的,再有其他方法就只能是空间换时间。
54 | 一种广泛采取的排序算法,是在数据量很大的时候,采取快速排序的方式,而在当分组很小的时候,使用其他稳定的排序方法。
55 | 这样的混合型算法,综合效果是最好的,也就是一般内置排序使用的方法
56 | '''
57 | def __init__(self):
58 | pass
59 |
60 | def straight_insertion_sort(self, lists):
61 | # 直接插入排序, 空间复杂度 o(1),时间复杂度为o(n^2),稳定排序
62 | if lists == [] or len(lists) == 1:
63 | return
64 | for i in range(1, len(lists)):
65 | key = lists[i]
66 | j = i-1
67 | while j >= 0:
68 | if lists[j] > key:
69 | lists[j+1] = lists[j]
70 | lists[j] = key
71 | j -= 1
72 | return lists
73 |
74 | def bubble_sort(self, lists):
75 | # 冒泡排序,快速排序的一种,稳定排序
76 | if lists == [] or len(lists) == 1:
77 | return lists
78 | for i in range(0, len(lists)):
79 | for j in range(i+1, len(lists)):
80 | if lists[i] > lists[j]:
81 | lists[j], lists[i] = lists[i], lists[j]
82 | return lists
83 |
84 | def quick_sort_1(self, lists):
85 | # 快速排序,对冒泡排序的改进,不稳定排序,时间复杂度为o(n*log 2n),目前公认的常数项因子最小的先进排序算法.
86 | # 其中的关键是分治策略,但是在 Python 中的分治要比 C 语言中的简单得多,但是我仍然用 Python 具体写了一下分治策略
87 | if lists == [] or len(lists) == 1:
88 | return lists
89 | low, high = 0, len(lists) - 1
90 | pivot = 0
91 | while low < high:
92 | while low < high:
93 | if lists[pivot] > lists[high]:
94 | lists[high], lists[low] = lists[low], lists[high]
95 | pivot = high
96 | break
97 | high -= 1
98 | while low < high:
99 | if lists[pivot] < lists[low]:
100 | lists[high], lists[low] = lists[low], lists[high]
101 | pivot = low
102 | break
103 | low += 1
104 | return self.quick_sort_1(lists[:pivot]) + [lists[pivot]] + self.quick_sort_1(lists[pivot+1:])
105 |
106 | def quick_sort_2(self, lists):
107 | # 快速排序的另外一种写法,简单写法,但是时间消耗要比分治多一些
108 | if lists == [] or len(lists) == 1:
109 | return lists
110 | left = [i for i in lists[1:] if i < lists[0]]
111 | right = [i for i in lists[1:] if i >= lists[0]]
112 | return self.quick_sort_2(left) + [lists[0]] + self.quick_sort_2(right)
113 |
114 | def shell_sort(self, lists):
115 | '''
116 | 希尔排序,插入排序的一种,时间复杂度为o(n^3/2),不稳定排序,基本思想是如果是正序的话,比较次数就少了很多
117 | i,j k 三个变量折腾的我有点懵逼,
118 | :param lists:
119 | :return:
120 | '''
121 | if lists == [] or len(lists) == 1:
122 | return lists
123 | count = len(lists)
124 | step = 2
125 | group = count / step
126 | while group > 0:
127 | for i in range(0, group):
128 | j = i + group
129 | while j < count:
130 | k = j - group
131 | key = lists[j]
132 | while k >= 0: # 直接插入排序的方法
133 | if lists[k] > key:
134 | lists[k + group] = lists[k]
135 | lists[k] = key
136 | k -= group
137 | j += group
138 | group /= step
139 | return lists
140 |
141 | def simple_select_sort(self, lists):
142 | '''
143 | 简单选择排序,稳定排序,时间复杂度为 o(n^2),查找每一次最小值的时候都要经过 n-1 次比较
144 | '''
145 | length = len(lists)
146 | for i in xrange(0, length):
147 | key = i
148 | for j in xrange(i+1, length):
149 | if lists[key] > lists[j]:
150 | key = j
151 | lists[i], lists[key] = lists[key], lists[i]
152 | return lists
153 |
154 | def heap_sort(self, L):
155 | '''
156 | 堆排序,是选择排序的一种优化,利用了树形结构,避免了选择最小元素时每次都经过 n-1 次比较,不稳定排序
157 | 辅助空间只需要一个,空间复杂度为o(1),时间复杂度为 o(n*log 2n),在最坏的情况下,复杂度依然是 o(n*log 2n)
158 | 这是相比快速排序优秀的地方,但是在序列中记录较少的时候不提倡使用,因为建立堆比较耗时。
159 | '''
160 | if L == [] or len(L) == 1:
161 | return L
162 |
163 | def sift_down(L, start, end): # 调整找到一颗根节点最小的树
164 | root = start
165 | while True:
166 | child = 2*root + 1 # 左子节点,一个辅助空间,指针指示哪一个节点
167 | if child > end: # 子节点超出范围
168 | break
169 | if child+1 <= end and L[child] < L[child+1]: # 左子节点比右子节点小,转换到右子节点
170 | child += 1
171 | if L[root] < L[child]: # 若根节点比 相对较大的一个子节点小,则互换
172 | L[root], L[child] = L[child], L[root]
173 | root = child # 进行树下面下一层的替换
174 | else:
175 | break
176 | return
177 | for start in range((len(L)-2)/2, -1, -1): # 逆序构建一个堆,堆顶的值最大,
178 | sift_down(L, start, len(L)-1)
179 | #print L
180 | for end in range(len(L)-1, 0, -1): # 取堆顶的一个值,放在序列尾部
181 | L[0], L[end] = L[end], L[0]
182 | sift_down(L, 0, end-1)
183 | return L
184 |
185 | def merging_sort(self, lists):
186 | '''
187 | 归并排序,需要的辅助空间大小和待排记录数量相等,时间复杂度也是 o(n*log 2n),稳定排序
188 | '''
189 | if lists == [] or len(lists) == 1:
190 | return lists
191 |
192 | def merge(list1, list2):
193 | i, j = 0, 0 # 分别指向两个序列的指针
194 | result = []
195 | while i < len(list1) and j < len(list2):
196 | if list1[i] > list2[j]:
197 | result.append(list2[j])
198 | j += 1
199 | else:
200 | result.append(list1[i])
201 | i += 1
202 | result += list1[i:]
203 | result += list2[j:]
204 | return result
205 |
206 | num = len(lists) / 2
207 | left = self.merging_sort(lists[:num])
208 | right = self.merging_sort(lists[num:])
209 | return merge(left, right)
210 |
211 | def bucket_sort(self, lists):
212 | '''
213 | 桶排序,非比较模型,适用于数据量非常大,数据紧凑,相同数据很多的情况,比如统计每年高考学生的分数
214 | '''
215 | if lists == [] or len(lists) == 1:
216 | return lists
217 | mini = min(lists) # 查找方法
218 | maxi = max(lists)
219 | bucket = []
220 | for _ in xrange(0, maxi+1-mini):
221 | bucket.append(0)
222 | for i in lists:
223 | bucket[i-mini] += 1
224 | res = []
225 | for i in xrange(0, len(bucket)):
226 | while bucket[i] > 0:
227 | res.append(i+mini)
228 | bucket[i] -= 1
229 | return res
230 |
231 | def radix_sort(self, lists):
232 | '''
233 | 基数排序,针对“正整数”来写的算法函数,稳定排序,按照千位、百位、十位来排序
234 | '''
235 | import math
236 | k = int(math.ceil(math.log(max(lists), 10)))
237 | bucket = [[] for _ in range(10)]
238 | for i in range(1, k+1):
239 | for j in lists:
240 | #num =
241 | bucket[(j%(10**i))/10**(i-1)].append(j)
242 | del lists[:]
243 | for z in bucket:
244 | lists += z
245 | del z[:]
246 | return lists
247 |
248 |
249 | class ExternalSortingAlgorithms(object):
250 | '''
251 | 败者树外部排序的全部实现:
252 | 1、使用gen_k_data 函数产生一个 data,这个data中,k表示归并的路数,l表示每一路中包含数字的个数
253 | e.g. data = gen_k_data(10, 200)
254 | print "generate the data for loser tree: ", data
255 | 2、在 merging_soring 函数中,接收上一步产生的数据。并首先生成一个败者树,在这一步中,关键点就是创建败者树,以及调整败者树。
256 | 然后,每次产生一个 compare,用来存放当前需要比较的10个数值,取出最小的一个,再从对应的那一路中取出下一个数值放在compare里
257 | 对应的位置上。如果某一路都取完了,我们就给该路的compare值赋一个很大的值,比如说我在这里赋了10000,当compare里全部都是10000
258 | 说明已经排序完毕,返回result 就是我们的排序结果。
259 | e. g. merging_sorting(data)
260 | '''
261 | def __init__(self):
262 | pass
263 |
264 | def gen_k_data(self, k, l): # 生成k 路随机数,并排序,存放在列表中, k表示归并的路数,l表示每一路多少个数
265 | if k < 0 or l < 0:
266 | print "Wrong given k number or l number."
267 | data = []
268 | sort = SortingAlgorithms()
269 | for n in xrange(0, k):
270 | merge = []
271 | small = random.randint(0, 100)
272 | large = random.randint(800, 1000)
273 | for _ in xrange(0, l):
274 | merge.append(random.randint(small, large)) # small 和 large 用来控制取值范围的。
275 | data.append(sort.heap_sort(merge))
276 | return data
277 |
278 | def merging_sorting(self, data): # 生成一个归并序列,把每一路中的元素挨个排入compare数组中
279 | k = len(data)
280 | compare = []
281 | for i in xrange(0, k):
282 | compare.append(data[i][0])
283 | #data[i].remove(data[i][0])
284 | print compare
285 |
286 | def adjust(loserTree, dataArray, n, s): # 败者树的核心代码
287 | t = (s + n) / 2
288 | while t > 0: # 从败者树的尾部开始进行比较
289 | if dataArray[s] > dataArray[loserTree[t]]: # 和败者结点比较
290 | s, loserTree[t] = loserTree[t], s # 如果比某个败者结点大,说明该结点失败了,将s结点存入败者树,把败者树的现在的胜结点拿去和其父节点比较。
291 | t /= 2
292 | loserTree[0] = s
293 |
294 | def createLoserTree(loserTree, dataArray, n):
295 | for i in range(n):
296 | loserTree.append(0)
297 | dataArray.append(i-n) # 这里是为了生成败者树用的,
298 |
299 | for i in range(n):
300 | adjust(loserTree, dataArray, n, n-1-i)
301 |
302 | loserTree = []
303 | dataArray = []
304 | createLoserTree(loserTree, dataArray, k)
305 |
306 | for i in xrange(k):
307 | dataArray[i] = compare[i] # 将数据替换成待排数据
308 | adjust(loserTree, dataArray, k, i) # 此步执行完毕,败者树才完全创建初始化完毕,正式开始排序归并
309 |
310 | result = []
311 | while True:
312 | if data[loserTree[0]][0] > 9999:
313 | break
314 | result.append(data[loserTree[0]][0]) # 添加到 result 中,这是我们需要的结果
315 | data[loserTree[0]].remove(data[loserTree[0]][0]) # 从data 中删除头一个元素
316 | if data[loserTree[0]] == []:
317 | data[loserTree[0]].append(10000)
318 | compare[loserTree[0]] = data[loserTree[0]][0] # 将下一个元素添加到 compare数组中
319 | adjust(loserTree, compare, k, loserTree[0])
320 |
321 | return result
322 |
323 | if __name__ == "__main__":
324 | sort = SortingAlgorithms()
325 | l = [4,90,125,2,9,47,999,-6,111,908,13,78,345,3,10]
326 | print "lists is :", l
327 | #print "Straight insertion sort: ", sort.straight_insertion_sort(l)
328 | # print "Bubble sort: ", sort.bubble_sort(l)
329 | # print "Quick sort 1: ", sort.quick_sort_1(l)
330 | # print "Quick sort 2: ", sort.quick_sort_2(l)
331 | #print "Shell sort: ", sort.shell_sort(l)
332 | #print "Simple select sort: ", sort.simple_select_sort(l)
333 | print "Heap sort: ", sort.heap_sort(l)
334 | print "Merging sort: ", sort.merging_sort(l)
335 | #print sort.bucket_sort(l)
336 |
337 | L = range(5000)
338 | random.shuffle(L)
339 |
340 | if __name__=="__main__":
341 | #unittest.main()
342 | print "radix_sort: ", sort.radix_sort(l)
343 |
344 |
--------------------------------------------------------------------------------
/string_algorithms/string_algorithms.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | class StringAlgorithm(object):
5 | def __init__(self):
6 | pass
7 |
8 | def is_rotation(self, str1, str2): # 判断两子串是否互为变形词
9 | if str1 == "" or str2 == "" or len(str1) != len(str2):
10 | return False
11 | str_double = str1 + str1
12 | if str2 in str_double:
13 | return True
14 | else:
15 | return False
16 |
17 | def str_2_int(self, string): # 将符合规范的数字字符串转为数字
18 | if string == "":
19 | return 0
20 | if len(string) == 1:
21 | if 48 < ord(string) <= 57:
22 | return ord(string) - 48
23 | else:
24 | return 0
25 | else: # 字符串长度大于 1
26 | num = 0
27 | if 48 < ord(string[0]) <= 57:
28 | num = ord(string[0])
29 | posi = 1
30 | elif string[0] == "-":
31 | if string[1] == "0":
32 | return 0
33 | posi = -1
34 | else:
35 | return 0
36 | for i in xrange(1, len(string)):
37 | if 48 <= ord(string[i]) <= 57:
38 | num = num * 10 + ord(string[i])
39 | else:
40 | return 0
41 | return num * posi
42 |
43 | def replace_str(self, string, from_str, to_str): # 替换字符串中连续出现的指定字符串,有问题####
44 | pass
45 |
46 | def get_count_str(self, string): # 获取字符串的统计字符串
47 | if string == "":
48 | return ""
49 | count = 0
50 | char = string[0]
51 | count_str = ""
52 | for i in xrange(0, len(string)):
53 | if char != string[i]:
54 | count_str += char + "_" + str(count) + "_"
55 | char = string[i]
56 | count = 1
57 | else:
58 | count += 1
59 | count_str += char + "_" + str(count)
60 | return count_str
61 |
62 | def is_unique_1(self, str_list): # 判断字符类型数组中的字符是否均只出现过一次,时间复杂度o(n)
63 | if str_list == "":
64 | return False
65 | i, map = 0, [0]
66 | while i < 256:
67 | map.append(0)
68 | i += 1
69 | for i in xrange(0, len(str_list)):
70 | map[ord(str_list[i])] += 1
71 | if map[ord(str_list[i])] != 1:
72 | return False
73 | return True
74 |
75 | def is_unique_2(self, str_list): # 判断字符类型数组中的字符是否均只出现过一次,空间复杂度o(1)######
76 | if str_list == "":
77 | return False
78 | for i in xrange(0, len(str_list)):
79 | for j in xrange(i + 1, len(str_list)):
80 | if str_list[i] == str_list[j]:
81 | return False
82 | return True
83 |
84 | def get_index(self, str_list, str): # 在有序但包含None的数组中查找字符
85 | index = -1
86 | left = 0
87 | right = len(str_list) - 1
88 | if str is None:
89 | return -1
90 | while left <= right:
91 | mid = (left + right) / 2
92 | if str_list[mid] == str:
93 | index = mid
94 | right = mid - 1
95 | elif str_list[mid] == None:
96 | i = mid - 1
97 | while 0 < i < mid:
98 | if str_list[i] != None:
99 | break
100 | else:
101 | i -= i
102 | if ord(str_list[i]) == ord(str):
103 | index = i
104 | right = i - 1
105 | elif ord(str_list[i]) > ord(str):
106 | right = i
107 | else:
108 | left = mid + 1
109 | else:
110 | if ord(str_list[mid]) > ord(str):
111 | right = mid - 1
112 | else:
113 | left = mid + 1
114 | return index
115 |
116 | def replace_space(self, str_list): # 字符串的调整与替换,时间复杂度o(n),空间复杂度o(1)
117 | num = 1
118 | for i in xrange(0, len(str_list)):
119 | if str_list[i] == ' ':
120 | num += 1
121 | length = len(str_list) + 2 * num - 2
122 | i = k = len(str_list)
123 | while i < length:
124 | str_list.append('0')
125 | i += 1
126 | i -= 1
127 | for j in xrange(k - 1, -1, -1):
128 | if str_list[j] == ' ':
129 | str_list[i] = "0"
130 | i -= 1
131 | str_list[i] = "2"
132 | i -= 1
133 | str_list[i] = "%"
134 | i -= 1
135 | else:
136 | str_list[i] = str_list[j]
137 | i -= 1
138 | return str_list
139 |
140 | def replace_stars(self, str_list): # 将所有*号移动到数组的左侧
141 | j = len(str_list) - 1
142 | for i in xrange(len(str_list) - 1, -1, -1):
143 | if str_list[i] != '*':
144 | str_list[j] = str_list[i]
145 | j -= 1
146 | for i in xrange(0, j + 1):
147 | str_list[i] = '*'
148 | return str_list
149 |
150 | def rotate_word(self, str_list): # 翻转字符串,将一句英文中的单词全部逆序,单词本身不变#####
151 | if str_list == []:
152 | return []
153 |
154 | def reverse_list(self, str_list, start, end): # 翻转一个数组,逆序存入同样的位置######
155 | if str_list == [] or start == end:
156 | return str_list
157 | if start > end:
158 | print "WRONG index."
159 | return str_list
160 | for i in xrange(0, (end - start) / 2):
161 | tmp = str_list[end - i]
162 | str_list[end - i] = str_list[start + i]
163 | str_list[start + i] = tmp
164 |
165 | def pattern_match(self, str, pattern): # 字符串的模式匹配,返回匹配到的索引
166 | index = []
167 | for _ in xrange(0, len(str)):
168 | i = _
169 | j = 0
170 | while j < len(pattern):
171 | if i < len(str) and str[i] == pattern[j]:
172 | i += 1
173 | j += 1
174 | else:
175 | break
176 | if j == len(pattern):
177 | index.append(_)
178 | return index
179 |
180 | def kmp_pattern_match(self, str, pattern):
181 | index = []
182 | j = 0
183 | for i in xrange(0, len(str)):
184 |
185 | def get_next(pattern, index): # index 范围为 1 到 len(pattern),算上 len(pattern)
186 |
187 | def next_index(pattern): # 返回一个列表,表示对应索引的下一跳索引
188 | next_list = [0, 0]
189 | for _ in xrange(2, len(pattern)):
190 | temp_list = [0]
191 | for i in xrange(1, _):
192 | if pattern[0:i] == pattern[_ - i:_]:
193 | temp_list.append(i)
194 | next_list.append(max(temp_list))
195 | return next_list
196 |
197 | next_list = next_index(pattern)
198 | return next_list[index]
199 |
200 | j = get_next(pattern, j)
201 | while j < len(pattern):
202 | if i < len(str) and str[i] == pattern[j]:
203 | i += 1
204 | j += 1
205 | else:
206 | break
207 | if j == len(pattern):
208 | index.append(i - j)
209 | j = 0
210 | return index
211 |
212 | def min_distance_1(self, strs, str1, str2):
213 | '''
214 | 数组中两个字符串的最小距离,这是方法1,时间复杂度 o(n^2)
215 | :param strs: 给定的数组中存放有多个字符串
216 | :param str1: 第一个字符串
217 | :param str2: 第二个字符串
218 | :return: 如果其中给定的一个字符串不在数组 strs 中,那么返回-1,否则返回两个字符串之间的最小间距
219 | '''
220 | if str1 not in strs or str2 not in strs:
221 | return -1
222 | if str1 == str2:
223 | return 0
224 | dist, min = 1, len(strs)
225 | pos1, pos2 = 0, len(strs)
226 | for i in xrange(0, len(strs)):
227 | if str1 == strs[i]:
228 | pos1 = i
229 | for j in xrange(0, len(strs)):
230 | if str2 == strs[j]:
231 | pos2 = j
232 | dist = abs(pos1 - pos2)
233 | if dist < min:
234 | min = dist
235 | return min
236 |
237 | def min_distance_2(self, strs, str1, str2):
238 | '''
239 | 数组中两个字符串的最小距离,这是方法2,如果查询的次数非常多,把每次查询的时间复杂度下降到 o(1)。
240 | Python 的内置 dict 类型就是哈希表,实现方法也是hash 表,其查询的时间复杂度就是 o(1)。哈希表的构造也分很多种:
241 | 比如,构造 Hash 表,key值是strs中的每一个字符串,value值是一个hash表,里面存放着该字符串到其它字符串的最小距离。
242 | 写成代码就是:hash_table = {"*":{"3":1, "5":1, "10":2, "9":3, "7":2, "1":1}}
243 | 当然这种方法的空间复杂度是 o(n^2)
244 | :param strs: 给定的数组中存放有多个字符串['*','3','*','5','10','9','7','1','*']
245 | :param str1: 第一个字符串, '*'
246 | :param str2: 第二个字符串, '9'
247 | :return: 如果其中给定的一个字符串不在数组 strs 中,那么返回-1,否则返回两个字符串之间的最小间距
248 | '''
249 | if str1 not in strs or str2 not in strs:
250 | return -1
251 | if str1 == str2:
252 | return 0
253 |
254 | def create_hash(strs): # 创建 Hash 表的过程,其实创建完后就不再更改了,这里为了方便说明就具体写了一下
255 | strs_set = list(set(strs))
256 | dist_hash = {}
257 | for i in xrange(0, len(strs_set)):
258 | temp = {}
259 | for j in xrange(0, len(strs_set)):
260 | if strs_set[i] != strs_set[j]:
261 | dist = self.min_distance_1(strs, strs_set[i], strs_set[j])
262 | temp[strs_set[j]] = dist
263 | dist_hash[strs_set[i]] = temp
264 | return dist_hash
265 |
266 | return create_hash(strs)[str1][str2]
267 |
268 | def brackets_is_valid_1(self, str):
269 | '''
270 | 判断括号字符串是不是有效括号字符串,比如:"()()"为 True,"(()())"为 True,"())","(())"等等均为 False
271 | 方法1:建立一个栈操作,时间复杂度为一遍遍历,但是空间复杂度较高。
272 | :param str: 括号字符串
273 | :return: True 或者 False
274 | '''
275 | stack = []
276 | for i in xrange(0, len(str)):
277 | if str[i] != "(" and str[i] != ")":
278 | return False
279 | if str[i] == "(":
280 | stack.append("(")
281 | else:
282 | stack.pop()
283 | if stack != []:
284 | return False
285 | else:
286 | return True
287 |
288 | def brackets_is_valid_2(self, str):
289 | '''
290 | 判断括号字符串是不是有效括号字符串,比如:"()()"为 True,"(()())"为 True,"())","(())"等等均为 False
291 | 方法2:时间复杂度不变,仍是一遍遍历的,但是空间复杂度只有o(1)。
292 | :param str: 括号字符串
293 | :return: True 或者 False
294 | '''
295 | num1, num2 = 0, 0
296 | for i in xrange(0, len(str)):
297 | if str[i] != "(" and str[i] != ")":
298 | return False
299 | if str[i] == "(":
300 | num1 += 1
301 | else:
302 | num2 += 1
303 | if num1 < num2:
304 | return False
305 | if num1 == num2:
306 | return True
307 | else:
308 | return False
309 |
310 | def longest_sub_brackets(self, str):
311 | '''
312 | 给定一个括号字符串 str,返回最长的有效括号字符串
313 | 方法:动态规划求解,做到时间复杂度 o(n),空间复杂度 o(n)。创建一个与字符串同等长度的数组 dp[],
314 | 其含义是对应 str[i]结尾的字符串的最长有效子串的长度。然后即可开始求解。
315 | :param str: 给定的括号字符串
316 | :return: 最长有效子串
317 | '''
318 | print str
319 | dp = []
320 | for _ in xrange(0, len(str)):
321 | dp.append(0)
322 | for i in xrange(0, len(str)):
323 | if str[i] == "(":
324 | dp[i] = 0
325 | if str[i] == ")":
326 | if i != 0:
327 | pre = i - dp[i - 1] - 1
328 | if str[pre] == "(":
329 | dp[i] = dp[i - 1] + 2 + dp[pre - 1]
330 | return max(dp)
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 | str_algo = StringAlgorithm()
339 | # print "is_deformation: ", str_algo. is_deformation("fefdw", "wef")
340 | # print "sum_of_num: ", str_algo.sum_of_num("a12b--2fe.8")
341 | # print "remove_k_zeros: ", str_algo.remove_k_zeros("0000fw300001203h000ui0000re3_0000", 4)
342 | # print "is_rotation: ", str_algo.is_rotation("bhfj", "jbfh")
343 | # print "str_2_int: ", str_algo.str_2_int("-3761aa29"), type(str_algo.str_2_int("376129"))
344 | # print "replace_str: ", str_algo.replace_str()
345 | print "get_count_str: ", str_algo.get_count_str("fffjkk99999022____")
346 | print "get_char_at: ", str_algo.get_char_at(str_algo.get_count_str("fffjkk99999022"), 14)
347 | print "is_unique_1: ", str_algo.is_unique_1("hdslegtr")
348 | print "is_unique_2: ", str_algo.is_unique_2("hdslecvb")
349 | print "get_index: ", str_algo.get_index(['a', None, 'b', None, 'd', 'd', None, 'k', 'm'], 'd')
350 | print "replace_space: ", str_algo.replace_space([' ', 'a', ' ', 'b', ' ', ' ', 'g'])
351 | print "replace_stars: ", str_algo.replace_stars(['*', '3', '*', '5', '9', '1', '*'])
352 |
353 | # print "min_distance_1: ", str_algo.min_distance_1(['*','3','*','5','10','9','7','1','*'], '*', '7')
354 | # print "min_distance_2: ", str_algo.min_distance_2(['*','3','*','5','10','9','7','1','*'], '*', '7')
355 | print "brackets_is_valid: ", str_algo.brackets_is_valid_1("(()(())())")
356 | print "brackets_is_valid: ", str_algo.brackets_is_valid_2("(()(())())")
357 | print "longest_sub_brackets", str_algo.longest_sub_brackets("(()(((&))(())")
358 |
--------------------------------------------------------------------------------
/linkedlist_algorithms/linkedlist_algorithms.py:
--------------------------------------------------------------------------------
1 | # -*- coding=utf-8 -*-
2 |
3 | import math
4 | from stack_algorithms import Stack
5 |
6 |
7 | class Node(object):
8 | def __init__(self, value, next=0):
9 | self.value = value
10 | self.next = next # 指针
11 |
12 |
13 | class LinkedList(object):
14 | # 链表的数据结构
15 | def __init__(self):
16 | self.head = 0 # 头部
17 |
18 | def __getitem__(self, key):
19 | if self.is_empty():
20 | print 'Linked list is empty.'
21 | return
22 | elif key < 0 or key > self.get_length():
23 | print 'The given key is wrong.'
24 | return
25 | else:
26 | return self.get_elem(key)
27 |
28 | def __setitem__(self, key, value):
29 | if self.is_empty():
30 | print 'Linked list is empty.'
31 | return
32 | elif key < 0 or key > self.get_length():
33 | print 'The given key is wrong.'
34 | return
35 | else:
36 | return self.set_elem(key, value)
37 |
38 | def init_list(self, data): # 按列表给出 data
39 | self.head = Node(data[0])
40 | p = self.head # 指针指向头结点
41 | for i in data[1:]:
42 | p.next = Node(i) # 确定指针指向下一个结点
43 | p = p.next # 指针滑动向下一个位置
44 |
45 | def get_length(self):
46 | p, length = self.head, 0
47 | while p != 0:
48 | length += 1
49 | p = p.next
50 | return length
51 |
52 | def is_empty(self):
53 | if self.head == 0:
54 | return True
55 | else:
56 | return False
57 |
58 | def insert_node(self, index, value):
59 | if index < 0 or index > self.get_length():
60 | print 'Can not insert node into the linked list.'
61 | elif index == 0:
62 | temp = self.head
63 | self.head = Node(value, temp)
64 | else:
65 | p, post = self.head, self.head
66 | for i in xrange(index):
67 | post = p
68 | p = p.next
69 | temp = p
70 | post.next = Node(value, temp)
71 |
72 | def delete_node(self, index):
73 | if index < 0 or index > self.get_length()-1:
74 | print "Wrong index number to delete any node."
75 | elif self.is_empty():
76 | print "No node can be deleted."
77 | elif index == 0:
78 | temp = self.head
79 | self.head = temp.next
80 | elif index == self.get_length():
81 | p = self.head
82 | for i in xrange(self.get_length()-2):
83 | p = p.next
84 | p.next = 0
85 | else:
86 | p = self.head
87 | for i in xrange(index-1):
88 | p = p.next
89 | p.next = p.next.next
90 |
91 | def show_linked_list(self): # 打印链表中的所有元素
92 | if self.is_empty():
93 | print 'This is an empty linked list.'
94 | else:
95 | p, container = self.head, []
96 | for _ in xrange(self.get_length()-1): #
97 | container.append(p.value)
98 | p = p.next
99 | container.append(p.value)
100 | print container
101 |
102 | def clear_linked_list(self): # 将链表置空
103 | p = self.head
104 | for _ in xrange(0, self.get_length()-1):
105 | post = p
106 | p = p.next
107 | del post
108 | self.head = 0
109 |
110 | def get_elem(self, index):
111 | if self.is_empty():
112 | print "The linked list is empty. Can not get element."
113 | elif index < 0 or index > self.get_length()-1:
114 | print "Wrong index number to get any element."
115 | else:
116 | p = self.head
117 | for _ in xrange(index):
118 | p = p.next
119 | return p.value
120 |
121 | def set_elem(self, index, value):
122 | if self.is_empty():
123 | print "The linked list is empty. Can not set element."
124 | elif index < 0 or index > self.get_length()-1:
125 | print "Wrong index number to set element."
126 | else:
127 | p = self.head
128 | for _ in xrange(index):
129 | p = p.next
130 | p.value = value
131 |
132 | def get_index(self, value):
133 | p = self.head
134 | for i in xrange(self.get_length()):
135 | if p.value == value:
136 | return i
137 | else:
138 | p = p.next
139 | return -1
140 |
141 | def reverse_linked_list(self): # 将链表逆序反转,返回的是头指针。
142 | if self.head == 0: # 空链表
143 | return self.head
144 | length = self.get_length()
145 | if length == 1:
146 | return self.head
147 | p = self.head
148 | head = self.head
149 | pre = 0
150 | while head != 0:
151 | p = p.next
152 | head.next = pre
153 | pre = head
154 | head = p
155 | self.head = pre
156 | return pre
157 |
158 | def reverse_part_linked_list(self, a, b):
159 | p = self.head
160 | if a == 0:
161 | tail, head = p, p
162 | pre = 0
163 | for _ in xrange(a, b+1):
164 | p = p.next
165 | head.next = pre
166 | pre = head
167 | head = p
168 | self.head = pre
169 | tail.next = p
170 | else:
171 | for _ in xrange(1, a):
172 | p = p.next
173 | front = p
174 | p = p.next
175 | tail = p
176 | pre = 0
177 | head = p
178 | for _ in xrange(a+1, b+2):
179 | p = p.next
180 | head.next = pre
181 | pre = head
182 | head = p
183 | front.next = pre
184 | tail.next = p
185 |
186 |
187 | l = LinkedList()
188 | print "The length of linked list now is: ", l.get_length()
189 | print l.is_empty()
190 | l.init_list([1, 5, 12, "fjd", 45, 999])
191 | print "The length of linked list now is: ", l.get_length()
192 | print l.is_empty()
193 | l.insert_node(4, 100)
194 | l.insert_node(6, "cecil")
195 | #l.show_linked_list()
196 | print "The value of index 0 is: ", l.get_elem(0)
197 | l.set_elem(0,1000)
198 | #l.show_linked_list()
199 | print "the index of *** is: ", l.get_index(1009)
200 | print "The length of linked list now is: ", l.get_length()
201 | l.delete_node(3)
202 | #l.clear_linked_list()
203 | #l.reverse_linked_list()
204 | #l.show_linked_list()
205 | l.reverse_part_linked_list(4, 6)
206 | #l.show_linked_list()
207 | print "****************************************"
208 |
209 |
210 | class RingLinkedList(object):
211 | # 链表的数据结构
212 | def __init__(self):
213 | self.head = 0 # 头部
214 |
215 | def __getitem__(self, key):
216 | if self.is_empty():
217 | print 'Linked list is empty.'
218 | return
219 | elif key < 0 or key > self.get_length():
220 | print 'The given key is wrong.'
221 | return
222 | else:
223 | return self.get_elem(key)
224 |
225 | def __setitem__(self, key, value):
226 | if self.is_empty():
227 | print 'Linked list is empty.'
228 | return
229 | elif key < 0 or key > self.get_length():
230 | print 'The given key is wrong.'
231 | return
232 | else:
233 | return self.set_elem(key, value)
234 |
235 | def init_list(self, data): # 按列表给出 data
236 | self.head = Node(data[0])
237 | p = self.head # 指针指向头结点
238 | for i in data[1:]:
239 | p.next = Node(i) # 确定指针指向下一个结点
240 | p = p.next # 指针滑动向下一个位置
241 | p.next = self.head
242 |
243 | def get_length(self):
244 | p, length = self.head, 0
245 | while p != 0:
246 | length += 1
247 | p = p.next
248 | if p == self.head:
249 | break
250 | return length
251 |
252 | def is_empty(self):
253 | if self.head == 0:
254 | return True
255 | else:
256 | return False
257 |
258 | def insert_node(self, index, value):
259 | length = self.get_length()
260 | if index < 0 or index > length:
261 | print 'Can not insert node into the linked list.'
262 | elif index == 0:
263 | temp = self.head
264 | self.head = Node(value, temp)
265 | p = self.head
266 | for _ in xrange(0, length):
267 | p = p.next
268 | #print "p.value", p.value
269 | p.next = self.head
270 | elif index == length:
271 | elem = self.get_elem(length-1)
272 | elem.next = Node(value)
273 | elem.next.next = self.head
274 | else:
275 | p, post = self.head, self.head
276 | for i in xrange(index):
277 | post = p
278 | p = p.next
279 | temp = p
280 | post.next = Node(value, temp)
281 |
282 | def delete_node(self, index):
283 | if index < 0 or index > self.get_length()-1:
284 | print "Wrong index number to delete any node."
285 | elif self.is_empty():
286 | print "No node can be deleted."
287 | elif index == 0:
288 | tail = self.get_elem(self.get_length()-1)
289 | temp = self.head
290 | self.head = temp.next
291 | tail.next = self.head
292 | elif index == self.get_length()-1:
293 | p = self.head
294 | for i in xrange(self.get_length()-2):
295 | p = p.next
296 | p.next = self.head
297 | else:
298 | p = self.head
299 | for i in xrange(index-1):
300 | p = p.next
301 | p.next = p.next.next
302 |
303 | def show_linked_list(self): # 打印链表中的所有元素
304 | if self.is_empty():
305 | print 'This is an empty linked list.'
306 | else:
307 | p, container = self.head, []
308 | for _ in xrange(self.get_length()-1): #
309 | container.append(p.value)
310 | p = p.next
311 | container.append(p.value)
312 | print container
313 |
314 | def clear_linked_list(self): # 将链表置空
315 | p = self.head
316 | for _ in xrange(0, self.get_length()-1):
317 | post = p
318 | p = p.next
319 | del post
320 | self.head = 0
321 |
322 | def get_elem(self, index):
323 | if self.is_empty():
324 | print "The linked list is empty. Can not get element."
325 | elif index < 0 or index > self.get_length()-1:
326 | print "Wrong index number to get any element."
327 | else:
328 | p = self.head
329 | for _ in xrange(index):
330 | p = p.next
331 | return p
332 |
333 | def set_elem(self, index, value):
334 | if self.is_empty():
335 | print "The linked list is empty. Can not set element."
336 | elif index < 0 or index > self.get_length()-1:
337 | print "Wrong index number to set element."
338 | else:
339 | p = self.head
340 | for _ in xrange(index):
341 | p = p.next
342 | p.value = value
343 |
344 | def get_index(self, value):
345 | p = self.head
346 | for i in xrange(self.get_length()):
347 | if p.value == value:
348 | return i
349 | else:
350 | p = p.next
351 | return -1
352 |
353 | ring = RingLinkedList()
354 | ring.init_list([2,5,9,12,37,49,88,91,100])
355 | ring.show_linked_list()
356 | ring.insert_node(0, 100)
357 | ring.show_linked_list()
358 | ring.delete_node(3)
359 | ring.show_linked_list()
360 | ring.clear_linked_list()
361 | ring.show_linked_list()
362 | print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"
363 |
364 |
365 | class LinkedListAlgorithms(object):
366 | # 所有的链表算法题
367 | def __init__(self):
368 | pass
369 |
370 | def print_common_part(self, head1, head2): # 给定两个链表的头指针,打印出公共的部分
371 | if head1.next == 0 or head2.next == 0:
372 | print 'No common part between two linked lists.'
373 | common = []
374 | while head1 is not None and head2 is not None:
375 | if head1.value > head2.value:
376 | head2 = head2.next
377 | elif head1.value < head2.value:
378 | head1 = head1.next
379 | else:
380 | common.append(head1.value)
381 | head1, head2 = head1.next, head2.next
382 | if head1 == 0 or head2 == 0:
383 | break
384 | print 'Common part: ', common
385 |
386 | def rm_last_kth_node(self, k, linked_list): # 删除倒数第 K 个节点,针对单链表的
387 | if linked_list.is_empty():
388 | print 'The given linked_list is empty.'
389 | if k < 1 or k > linked_list.get_length():
390 | print 'Wrong kth number out of index.'
391 | k = linked_list.get_length() - k
392 | if k == 0:
393 | p = linked_list.head
394 | linked_list.head = p.next
395 | else:
396 | p = linked_list.head
397 | for i in xrange(k-1):
398 | p = p.next
399 | p.next = p.next.next
400 |
401 | def rm_mid_node(self, head): # 给定一个链表,删除它的中间的一个结点,返回头指针
402 | if head == 0:
403 | return head
404 | p = head
405 | length = 1
406 | while p != 0:
407 | length += 1
408 | p = p.next
409 | if length == 1:
410 | return head
411 | mid = length / 2
412 | for _ in xrange(1, mid-1):
413 | head = head.next
414 | head.next = head.next.next
415 | return head
416 |
417 | def rm_by_ratio(self, head, a, b): # 给定一个链表,删除它按比例的 a/b处的一个结点,返回头指针
418 | if a > b:
419 | print "The given a should be lower than b."
420 | return head
421 | if head == 0:
422 | return head
423 | p = head
424 | length = 1
425 | while p != 0:
426 | length += 1
427 | p = p.next
428 | if length == 1:
429 | return head
430 | ratio = length*float(a)/float(b)
431 | for _ in xrange(1, int(math.ceil(ratio))-1):
432 | head = head.next
433 | head.next = head.next.next
434 | return head
435 |
436 | def reverse_linked_list(self, head): # 将链表逆序反转,返回头指针
437 | if head == 0: # 空链表
438 | return head
439 | p = head
440 | length = 1
441 | while p != 0:
442 | length += 1
443 | p = p.next
444 | if length == 1:
445 | return head
446 | p = head
447 | pre = 0
448 | while head != 0:
449 | p = p.next
450 | head.next = pre
451 | pre = head
452 | head = p
453 | return pre
454 |
455 | def reverse_part_linked_list(self, head, a, b): # 反转部分链表结点,a, b分别为索引值
456 | if head == 0:
457 | print "Empty linked list. No need to reverse."
458 | return head
459 | p = head
460 | length = 1
461 | while p != 0:
462 | length += 1
463 | p = p.next
464 | if length == 1:
465 | print "No need to reverse."
466 | return head
467 | if a < 0 or b > length-1 or a >= b:
468 | raise Exception("The given 'from' value and 'to' value is wrong.")
469 | p = head
470 |
471 | if a == 0: # 由于 for 循环中 xrange 的范围问题,我就分情况写了。
472 | tail, head = p, p
473 | pre = 0
474 | for _ in xrange(a, b+1):
475 | p = p.next
476 | head.next = pre
477 | pre = head
478 | head = p
479 | tail.next = p
480 | return head
481 | else:
482 | for _ in xrange(1, a):
483 | p = p.next
484 | front, tail, head = p, p, p
485 | p = p.next
486 | pre = 0
487 | for _ in xrange(a+1, b+2):
488 | p = p.next
489 | head.next = pre
490 | pre = head
491 | head = p
492 | front.next = pre
493 | tail.next = p
494 | return head
495 |
496 | def is_palindrome1(self, head):
497 | '''
498 | 判断一个链表是否是回文结构,如果是返回 True,否则返回 False
499 | 方法1:时间复杂度o(n),空间复杂度o(n)
500 | '''
501 | if head == 0 or head.next == 0:
502 | return True
503 | p = head
504 | stack = Stack() # 自定义的 Stack 数据结构,也可以使用python内置的 list来实现
505 | while p != 0:
506 | stack.push(p.value)
507 | p = p.next
508 | p = head
509 | while p != 0:
510 | if p.value != stack.pop():
511 | return False
512 | p = p.next
513 | return True
514 |
515 | def is_palindrome2(self, head):
516 | '''
517 | 判断一个链表是否是回文结构,如果是返回 True,否则返回 False
518 | 方法2:时间复杂度o(n),空间复杂度o(1),方法是将链表的右半边逆序反转一下,然后逐个比较,如果有不同,则返回错误
519 | '''
520 | p, length = head, 0
521 | while p != 0:
522 | length += 1
523 | p = p.next
524 |
525 | mid = (length+1) / 2 - 1
526 | p = head
527 | for _ in xrange(mid):
528 | p = p.next
529 |
530 | mid_node = p # 获取中间节点
531 | tail = mid_node.next
532 | mid_node.next = 0
533 |
534 | pre = mid_node
535 | while tail != 0:
536 | p = tail.next
537 | tail.next = pre
538 | pre = tail
539 | tail = p
540 |
541 | p = head
542 | tail = pre
543 | #print "p.value", p.value, p.next.value, p.next.next.value, p.next.next.next
544 | #print "tail.value:", pre.value, pre.next.value, pre.next.next.value, pre.next.next.next.value
545 | while p != 0:
546 | #print "p.value:", p.value, "tail.value:", tail.value
547 | if p.value != pre.value: # 分别从两头遍历链表,如果遍历到0,则说明已经遍历到头了。
548 | pre = 0
549 | while tail != 0:
550 | next = tail.next
551 | tail.next = pre
552 | pre = tail
553 | tail = next
554 | mid_node.next = pre.next
555 | return False
556 | else:
557 | p = p.next
558 | pre = pre.next
559 | pre = 0
560 | while tail != 0:
561 | next = tail.next
562 | tail.next = pre
563 | pre = tail
564 | tail = next
565 | mid_node.next = pre.next
566 | return True
567 |
568 | def josephus_kill_1(self, head, m):
569 | '''
570 | 环形单链表,使用 RingLinkedList 数据结构,约瑟夫问题。
571 | :param head:给定一个环形单链表的头结点,和第m个节点被杀死
572 | :return:返回最终剩下的那个结点
573 | 本方法比较笨拙,就是按照规定的路子进行寻找,时间复杂度为o(m*len(ringlinkedlist))
574 | '''
575 | if head == 0:
576 | print "This is an empty ring linked list."
577 | return head
578 | if m < 2:
579 | print "Wrong m number to play this game."
580 | return head
581 | p = head
582 | while p.next != p:
583 | for _ in xrange(0, m-1):
584 | post = p
585 | p = p.next
586 | #print post.next.value
587 | post.next = post.next.next
588 | p = post.next
589 | return p
590 |
591 | def list_partition(self, head, pivot):
592 | '''
593 | 将单向链表按某个值划分成左边小,中间相等,右边大的形式
594 | :param head:单向普通链表的头结点
595 | :param pivot:中间相等的那个数值
596 | :return:返回新的单向链表,左边和右边的结点顺序和原链表中的顺序一致。
597 | 方法1:最常见的算法就是重新开辟三个链表,分别存储small ,middle,和large的值,时间复杂度为链表长度,空间复杂度也是
598 | 方法2:把空间复杂度降到o(1),就是需要不停地调整链表中的位置
599 | '''
600 | if head == 0:
601 | print "This is an empty linked list."
602 | return
603 | sh, st, eh, et, lh, lt = 0, 0, 0, 0, 0, 0
604 | p = head
605 | while p != 0:
606 | if p.value < pivot:
607 | if sh == 0:
608 | sh = p
609 | st = p
610 | else:
611 | st.next = p
612 | st = st.next
613 | elif p.value == pivot:
614 | if eh == 0:
615 | eh = p
616 | et = p
617 | else:
618 | et.next = p
619 | et = et.next
620 | else:
621 | if lh == 0:
622 | lh = p
623 | lt = p
624 | else:
625 | lt.next = p
626 | lt = lt.next
627 | p = p.next
628 |
629 | if sh != 0 and eh != 0 and lh != 0:
630 | head = sh
631 | st.next = eh
632 | et.next = lh
633 | lt.next = 0
634 | elif sh == 0 and eh != 0 and lh != 0:
635 | head = eh
636 | et.next = lh
637 | lh.next = 0
638 | elif sh == 0 and eh == 0 and lh != 0:
639 | head = lh
640 | lh.next = 0
641 | elif sh == 0 and eh != 0 and lh == 0:
642 | head = eh
643 | et.next = 0
644 | elif sh != 0 and eh == 0 and lh == 0:
645 | head = sh
646 | st.next = 0
647 | elif sh != 0 and eh != 0 and lh == 0:
648 | head = sh
649 | st.next = eh
650 | et.next = 0
651 | elif sh != 0 and eh == 0 and lh != 0:
652 | head = sh
653 | st.next = lh
654 | lt.next = 0
655 | return head
656 |
657 | def copy_list_with_random_pointer(self, head):
658 | '''
659 | 一种特殊类型的链表结构,每一个节点都有一个随机指针域,指针指向该链表中随机一个结点,也有可能指向0.
660 | 复制含有随机指针结点的链表,比如一个单链表中有1->2->3->None,其中1还指向了3,2指向了None。
661 | 将整个数据结构都复制一遍,并返回头结点head,时间复杂度为一遍遍历该种链表,空间复杂度为o(1)。
662 | '''
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 | l1 = LinkedList()
673 | l1.init_list([1, 5, 12, 33, 45, 171, 999, 1001, 2000])
674 | l2 = LinkedList()
675 | l2.init_list([2, 5, 12,198, 12, 5, 2])
676 | l3 = LinkedList()
677 | l3.init_list([21, 5, 120, 19, 72, 50, 312])
678 |
679 | ll_algo = LinkedListAlgorithms()
680 | # ll_algo.print_common_part(l1.head, l2.head)
681 | # ll_algo.rm_last_kth_node(6, l1)
682 | # ll_algo.rm_mid_node(l2.head)
683 | # ll_algo.rm_by_ratio(l1.head, 41, 170)
684 | print "999"
685 | #l1.show_linked_list()
686 | # ll_algo.reverse_linked_list(l1.head)
687 | print "is palindrome1: ", ll_algo.is_palindrome1(l2.head)
688 | print "is palindrome2: ", ll_algo.is_palindrome2(l2.head)
689 | print "888"
690 | l2.show_linked_list()
691 | print "##################################################"
692 |
693 | ring = RingLinkedList()
694 | ring.init_list([2,5,9,12,37,49,88,91,100])
695 | print ll_algo.josephus_kill_1(ring.head, 4).value
696 | ll_algo.list_partition(l3.head, 100)
697 | l3.show_linked_list()
698 |
699 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | true
66 | DEFINITION_ORDER
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 | project
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 | 1509879019950
388 |
389 |
390 | 1509879019950
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
--------------------------------------------------------------------------------