def inverse_pair(a, n): ''' 打印逆序对儿,如输入数组[1,2,5,4,3],输出(5,4),(5,3),(4,3) ''' for i in range(n): for j in range(i+1, n): if a[i] > a[j]: print('(%d, %d)'%(a[i], a[j]), end='') a = [1,2,5,4,3] inverse_pair(a, len(a)) #(5,4),(5,3),(4,3)
归并排序可否记得,先通过二分法不断拆分整个序列,然后再在合并过程中两两组合,实现排序,而此题就是采用归并排序的思想,只不过在合并的过程中是两两前后比较,输出逆序对
def output_merge(a, start_idx, middle_idx, end_idx): '''merge合并过程输出逆序对''' for i in range(start_idx, middle_idx+1): for j in range(middle_idx+1, end_idx+1): if a[i] > a[j]: print((a[i], a[j]), end='') def inverse_pair_merge(a, start_idx, end_idx): '''递归实现对数组进行拆分''' if start_idx < end_idx: middle_idx = int((start_idx + end_idx)/2) inverse_pair_merge(a, start_idx, middle_idx) inverse_pair_merge(a, middle_idx+1, end_idx) output_merge(a, start_idx, middle_idx, end_idx) a = [5, 4, 3, 2, 1] inverse_pair_merge(a, 0, len(a)-1) #(5, 4)(5, 3)(4, 3)(2, 1)(5, 2)(5, 1)(4, 2)(4, 1)(3, 2)(3, 1)
(1) 假如现在有两个两个矩阵A(m, n)、B(n, n),普通矩阵三次for循环便实现矩阵乘法,但首先明白此题是系数矩阵;
(2) 系数矩阵:在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律,因此对于稀疏矩阵,里含有大量的零元素,如果按照正常的方式进行运算,则会耗费很多的无用功,矩阵元素相乘:c[i][j] = a[i][k] * b[k][j], 因此当判断矩阵A、B对应元素均非零时,才计算
def mat_mul(a, b): c = np.asarray(np.zeros((a.shape[0], b.shape[1]))) for i in range(a.shape[0]): for k in range(a.shape[1]): if a[i][k] != 0: for j in range(b.shape[1]): c[i][j] += a[i][k] * b[k][j] if b[k][j] != 0 else 0 return c a = np.asarray([[0, 0, 1, 0], [2, 0, 1, 0], [0, 0, 1, 2]]) b = np.asarray([[0, 1, 0], [1, 0, 0], [1, 1, 0], [1, 2, 0]]) c = mat_mul(a, b)
审题: 二叉树,可能是完全二叉树,也可能是非完全二叉树
本题我们全面分析一下,尝试从两种情况去考虑
思路: 先计算出两个节点在路上的高度, 例如为h1、h2(存在h1 >= h2),先将高度为h1的节点通过寻找父节点往上迭代 node1 = node1.parent,直到当前node1节点的高度now_h1 = h2,此时node1和node2节点高度相同,同时向上索引父节点,当二者的父节点相等时,则便是node1和node2的最近公共祖先
def height(node): '''求节点的高度''' node_height = 0 while node.parent != None: node_height += 1 node = node.parent return node_height def common_parent(root, node1, node2): '''查找二叉树任意两个节点的最近公共祖先''' node1_height = height(node1) node2_height = height(node2) while node1_height < node2_height: node2_height -= 1 node2 = node2.parent while node1_height > node2_height: node1_height -= 1 node1 = node1.parent while node1 and node2 and node1 != node2: node1 = node1.parent node2 = node2.parent if node1 == node2: return node1 else: return None
思路1: A、首先判断这两个节点是否等于根节点root, 如果是则root便是最近公共父节点 B、否则递归左、右子树,如果一个节点在左子树,一个节点在右子树, 则根节点root就是最近公共父节点,否则如果两个节点都在左子树, 则最近公共父节点都在左子树,否则都在右子树
def last_common_parent2(root, node1, node2): if root == None or node1 == None or node2 == None: return None #如果两个节点中有一个等于该子树的根节点,则直接返回子树的根节点 if node1 == root or node2 == root: return root #递归左子树和右子树 left_lca = last_common_parent2(root.lnode, node1, node2) right_lca = last_common_parent2(root.rnode, node1, node2) #如果左右子树返回值都不为None,则说明返回在node1 == root or node2 == root处返回的,则返回None if left_lca and right_lca: return root #如果返回的是left_lca为None,则说明左子树找到地也没有找到,则两个节点都在右子树,则返回right_lca #如果返回的是right_lca为None,则说明y右子树找到地也没有找到,则两个节点都在左子树,则返回left_lca if left_lca == None: return right_lca else: return left_lca
思路2: A、找到从根root到node1的路径,然后存放在数组和链表中 B、找到从根root到node2的路径,然后存放在数组和链表中 C、从两个数组或链表的开始往下访问,当遇到不同的节点时,则上一个节点便是最近公共子节点
def find_path(pnode, node, queue): ''' 给出一棵树和一个节点,查找根节点到这个节点的路径 使用队列结构存储路径 ''' find = False queue.put(pnode) if pnode == node: return True, queue #这里的return 返回是为了给find赋值的 if pnode.lnode != None: find, _ = find_path(pnode.lnode, node, queue) if not find and pnode.rnode != None: find, _ = find_path(pnode.rnode, node, queue) if not find: queue.get() return find, queue def last_common_parent3(root, node1, node2): ''' 查找二叉树任意两个节点的最近公共祖先 ''' _, queue1 = find_path(root, node1, LifoQueue()) _, queue2 = find_path(root, node2, LifoQueue()) plist1 = [] plist2 = [] while not queue1.empty(): plist1.append(queue1.get()) while not queue2.empty(): plist2.append(queue2.get()) plist1, plist2 = plist1[::-1], plist2[::-1] flag = False pnode = None for i in range(min(len(plist1), len(plist2))): if plist1[i] == plist2[i]: continue else: pnode = plist1[i-1] flag = True break #当找到不同点时,就跳出循环 if not flag: pnode = plist1[-1] if len(plist1) < len(plist2) else plist2[-1] return pnode
此处建立一棵二叉树供测试使用
class Tree: def __init__(self, data, lnode=None, rnode=None, parent=None): self.data = data self.lnode = lnode self.rnode = rnode self.parent = parent #手动建立二叉树,非完全二叉树 a = [5, 3, 4, 1, 6, 7, 8, 2, 9] a = list(map(lambda x: Tree(x), a)) root = a[0] a[0].lnode, a[0].rnode = a[1], a[2] a[1].parent, a[1].lnode, a[1].rnode = a[0], a[3], a[4] a[2].parent, a[2].lnode, a[2].rnode = a[0], a[5], a[6] a[3].parent, a[3].lnode = a[1], a[7] a[4].parent, a[4].rnode = a[1], a[8] a[5].parent, a[6].parent, a[7].parent, a[8].parent = a[2], a[2], a[3], a[4]
假设数组为a[0:n],最大和子数组为a[i:j],注意最大和子数组有这样的特点: (1) 从a[i-1]开始往左(下标减小方向)累加和,和都为负。(因为一旦和为正,这段累加和对应的子数组便可以并入a[i:j]构成更大和) (2) 从a[i]开始往右累加和, 在到达a[j]前,和都为正,且累加到a[j]时和最大
算法步骤: A、 给两个变量,now_sum和max_sum,now_sum初始化为0,max_sum初始化为负无穷; B、 从a[1]开始遍历,并把元素值累加给now_sum,一旦now_sum为负数,就清零; C、 在now_sum变化时,max_sum始终保留最大的now_sum; D、 如果最后now_sum和max_sum都是负数,输出最大的负值
def max_seq_of_array(a, n): ''' 一个数组,元素可能正可能负,求连续的子数组里,和最大的那个 Args: a: 数组 n:数组长度 Return: 连续子数组最大和 ''' now_sum = 0 max_sum = -float('inf') for i in range(n): now_sum += a[i] if now_sum > max_sum: max_sum = now_sum eidx = i if now_sum <= 0: now_sum = 0 return max_sum a = [-1,-2,-3,1,2,3,-3,4] max_seq_of_array(a, len(a))
注意:rand5():随机产生整数1-5,rand7()既是随机产生整数1-7
思路: 考虑问题是从数据映射的角度去考虑,肯定是需要两次调用rand5(), 先扩大数据产生更大的数然后缩小数据往1-7上进行映射
def rand5(): ''' 1-5的随机生成器 ''' return random.randint(1, 5) def rand7(): ''' 现有一个rand5()的随机数生成器,等可能生成1~5之间的数,要求用它实现rand7(),等可能生成1~7之间的数 ''' n = float('inf') while(n>=21): a = rand5() b = rand5() n = (a-1)*5 + b return int(n/3)+1
注意:显然这是最基础的排序,但还别说,能干到一片猿类,不是说大家不会放在平时都会写,但现场那点时间如果不能随手就写出来,靠着慢慢想还真是容易出错,所以大家平时要记住这些基础算法的思路,别sort()函数调用习惯了,排序也都不会写了
网上关于归并排序、快速排序和堆排序解释很多,这里不重复,直接粘上代码
归并排序
def merge_array(a, start_index, mid_index, end_index): ''' 合并两个有序数组成一个有序数组 Args: a = [] 待排序数组 start_index = 数组开始索引值 mid_index = 数组中间索引值,区分开两个有序数组 end_index = 数组结束索引值 Return: a = [] 合并的有序数组 ''' i, j = start_index, mid_index + 1 m, n = mid_index, end_index temp_list = [] while i <= m and j <= n: if a[i] <= a[j]: temp_list.append(a[i]) i += 1 else: temp_list.append(a[j]) j += 1 while j <= n: temp_list.append(a[j]) j += 1 while i <= m: temp_list.append(a[i]) i += 1 for index in range(len(temp_list)): a[start_index + index] = temp_list[index] def merge_sort(a, start_index, end_index): ''' 归并排序核心函数 Args: a = [] 待排序数组 start_index = 数组开始索引值 end_index = 数组结束索引值 Return: a = [] 完成排序数组 ''' if start_index < end_index: mid_index = (start_index + end_index)/2 merge_sort(a, start_index, mid_index) merge_sort(a, mid_index + 1, end_index) merge_array(a, start_index, mid_index, end_index) a = [3, 4, 1, 2, 9, 6, 5, 7, 12, 11, 10] merge_sort(a, 0, len(a) - 1)
快速排序
def quict_sort(a, start_index, end_index): ''' 快速排序核心函数 Args: a = [] 待排序数组 start_index = 数组开始索引值 end_index = 数组结束索引值 Return: a = [] 完成排序数组 ''' #if条件是递归结束条件 if start_index >= end_index: return boundary_index = quick_boundary(a, start_index, end_index) quict_sort(a, start_index, boundary_index - 1) quict_sort(a, boundary_index + 1, end_index) return a def quick_boundary(a, start_index, end_index): ''' 快速排序获取拆分边界索引值辅助函数 Args: a = [] 待排序数组的拆分 start_index = 拆分数组开始索引值 end_index = 拆分数组结束索引值 Return: boundary_index = Int 边界索引值 ''' boundary_index = start_index standard = a[boundary_index] left_index, right_index = start_index, end_index while left_index < right_index: while left_index < right_index and standard <= a[right_index]: right_index -= 1 a[left_index] = a[right_index] while left_index < right_index and standard >= a[left_index]: left_index += 1 a[right_index] = a[left_index] a[left_index] = standard boundary_index = left_index print(boundary_index) print(a) return boundary_index a = [49, 38, 65, 97, 76, 13, 27, 49] quict_sort(a, 0, len(a) - 1)
堆排序
def adjustheap(a, i, n): '''调整堆''' j = 2*i + 1 while j < n: if j+1 < n and a[j] < a[j+1]: j += 1 if a[j] < a[i]: break a[i], a[j] = a[j], a[i] i = j j = 2*i + 1 def makeheap(a, n): '''建堆''' for i in range(int(n/2)-1, -1, -1): adjustheap(a, i, n) def heapsort(a, n): '''堆排序''' makeheap(a, n) for i in range(n-1, -1, -1): a[i], a[0] = a[0], a[i] adjustheap(a, 0, i) a = [5, 2, 3, 1, 6, 8, 7, 4] heapsort(a, len(a))