Algorithms D6. Binary Tree

面试究竟考察哪些呢?主要是以下这些: 算法部分: 1. 快排 Quick Sort 2. 双指针 Two Pointers 3. 二分搜索 Binary Search 4. 深度优先搜索 Depth First Search 5. 宽度优先搜索 Breadth First Search 6. 分治 Divide Conquer 7. 回溯法 Backtracking 8. 动态规划 Dynamic Programming 9. 扫描线 Scan-line algorithm 数据结构部分: 1. 链表 Linked List 2. 栈 Stack 3. 队列 Queue 4. 数组 Array 5. 哈希表 Hash Table 6. 二叉树 Binary Tree 7. 堆 Heap 8. 并查集 Union Find 9. 字典树 Trie 基本知识 树 树的概念 树(tree)是一种能够分层存储数据的重要数据结构,树中的每个元素被称为树的节点,每个节点有若干个指针指向子节点。从节点的角度来看,树是由唯一的起始节点引出的节点集合。这个起始结点称为根(root)。树中节点的子树数目称为节点的度(degree)。在面试中,关于树的面试问题非常常见,尤其是关于二叉树(binary tree),二叉搜索树(Binary Search Tree, BST)的问题。 所谓的二叉树,是指对于树中的每个节点而言,至多有左右两个子节点,即任意节点的度小于等于2。而广义的树则没有如上限制。二叉树是最常见的树形结构。二分查找树是二叉树的一种特例,对于二分查找树的任意节点,该节点存储的数值一定比左子树的所有节点的值大比右子树的所有节点的值小“(与之完全对称的情况也是有效的:即该节点存储的数值一定比左子树的所有节点的值小比右子树的所有节点的值大)。 基于这个特性,二分查找树通常被用于维护有序数据。二分查找树查找、删除、插入的效率都会于一般的线性数据结构。事实上,对于二分查找树的操作相当于执行二分搜索,其执行效率与树的高度(depth)有关,检索任意数据的比较次数不会多于树的高度。这里需要引入高度的概念:对一棵树而言,从根节点到某个节点的路径长度称为该节点的层数(level),根节点为第0层,非根节点的层数是其父节点的层数加1。树的高度定义为该树中层数最大的叶节点的层数加1,即相当于于从根节点到叶节点的最长路径加1。由此,对于n个数据,二分查找树应该以“尽可能小的高度存储所有数据。由于二叉树第L层至多可以存储 2L 个节点,故树的高度应在logn量级,因此,二分查找树的搜索效率为O(logn)。 直观上看,尽可能地把二分查找树的每一层“塞满”数据可以使得搜索效率最高,但考虑到每次插入删除都需要维护二分查找树的性质,要实现这点并不容易。特别地,当二分查找树退化为一个由小到大排列的单链表(每个节点只有右孩子),其搜索效率变为O(n)。为了解决这样的问题,人们引入平衡二叉树的概念。所谓平衡二叉树,是指一棵树的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。通过恰当的构造与调整,平衡二叉树能够保证每次插入删除之后都保持平衡性。平衡二叉树的具体实现算法包括AVL算法和红黑算法等。由于平衡二叉树的实现比较复杂,故一般面试官只会问些概念性的问题。 二叉树 二叉树定义 二叉树是有限个结点的集合,这个集合或者是空集,或者是由一个根结点和两株互不相交的二叉树组成,其中一株叫根的做左子树,另一棵叫做根的右子树。 二叉树性质 性质1:在二叉树中第 i 层的结点数最多为2^(i-1)(i ≥ 1); 性质2:高度为k的二叉树其结点总数最多为2^k-1( k ≥ 1); 性质3:对任意的非空二叉树 T ,如果叶结点的个数为 n0,而其度为 2 的结点数为 n2,则:`n0 = n2 + 1; 满二叉树 深度为k且有2^k -1个结点的二叉树称为满二叉树; 完全二叉树 深度为 k 的,有n个结点的二叉树,当且仅当其每个结点都与深度为 k 的满二叉树中编号从 1 至 n 的结点一一对应,称之为完全二叉树。(除最后一层外,每一层上的节点数均达到最大值;在最后一层上只缺少右边的若干结点);...

8 min · 1553 words · Me

Algorithms DP-01 LPS

Dynamic Programming Leetcode 5. Longest Palindromic Substring Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000. Example 1: Input: "babad" Output: "bab" Note: "aba" is also a valid answer. Example 2: Input: "cbbd" Output: "bb" 解题思路 1. 根据回文类型 将回文串分为三种: 第一种是对称式回文串,比如:acddca 第二种是重复式的,比如:aaaaa 第三种是夹心饼干使的:acbbca 针对这三种情况来分析 C代码 2. 马拉车(Maracher)算法 马拉车(Maracher)算法 这道题用c语言的马拉车算法反而更耗时,因为需要频繁地申请内存,可能其他语言会更加高效。 C代码

1 min · 62 words · Me

Algorithms Q & A

Q 每瓶啤酒2元,2个空酒瓶或4个瓶盖可换1瓶啤酒。先付钱再喝酒,不能赊账,请实现一个函数计算N元钱最多可喝多少瓶啤酒? A int getSum(int n) { if(n < 2) return 0; int x = n / 2; int y = n / 2; int sum = x; //printf("%d %d %d\n", x, y, sum); while (x >= 2 || y >= 4) { while(x >= 2) { sum += 1; x -= 2; x += 1; y += 1; } while(y >= 4) { sum += 1; x += 1; y -= 4; y += 1; } } //printf("%d\n", sum); return sum; }

1 min · 83 words · Me

Algorithms 十大排序算法总结

1. 排序算法分类 在计算机科学所使用的排序算法通常被分类为: 计算的时间复杂度(最差、平均、和最好性能),依据列表(list)的大小(n)。一般而言,好的性能是 O(nlogn)(大O符号),坏的性能是 O(n^2)。对于一个排序理想的性能是 O(n),但平均而言不可能达到。基于比较的排序算法对大多数输入而言至少需要 O(nlogn)。 内存使用量(以及其他计算机资源的使用)。 稳定性:稳定排序算法会让原本有相等键值的纪录维持相对次序。也就是如果一个排序算法是稳定的,当有两个相等键值的纪录 R和 S,且在原本的列表中 R出现在 S之前,在排序过的列表中 R也将会是在 S之前。 依据排序的方法:插入、交换、选择、合并等等。 1.1 稳定性 稳定排序算法会依照相等的关键(换言之就是值)维持纪录的相对次序。也就是一个排序算法是稳定的,就是当有两个有相等关键的纪录R和S,且在原本的串行中R出现在S之前,在排序过的串行中R也将会是在S之前。 1.2 计算复杂度 依据串行(list)的大小(n),一般而言,好的表现是O(nlogn),且坏的行为是O(n2)。对于一个排序理想的表现是O(n)。仅使用一个抽象关键比较运算的排序算法总平均上总是至少需要O(nlogn)。 所有基于比较的排序的时间复杂度至少是 O(nlogn)。 1.3 常用排序算法 排序方法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最好) 空间复杂度 稳定性 冒泡排序 O(n^2) O(n^2) O(n) O(1) 稳定 插入排序 O(n^2) O(n^2) O(n) O(1) 稳定 选择排序 O(n^2) O(n^2) O(n^2) O(1) 不稳定 快速排序 O(nlogn) O(n^2) O(nlogn) O(nlogn) 不稳定 希尔排序 O(nlogn) O(n^2) O(n) O(1) 不稳定 堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定 归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定 桶排序 O(n+k) O(n^2) O(n) O(n+k) 稳定 基数排序 O(n*k) O(n*k) O(n*k) O(n+k) 稳定 计数排序 O(n+k) O(n+k) O(n+k) O(n+k) 稳定 2....

8 min · 1524 words · Me

APUE 7-进程环境

7.1 引言 当进程执行时,其main函数是如何被调用的; 命令行参数是如何传递给新进程的; 典型的存储空间布局的样式; 如何分配另外的存储空间; 进程如何使用环境变量; 进程的不同终止方式; longjmp和setjmp函数以及它们与栈的交互作用; 进程资源限制; 7.2 main函数 C程序总是从main函数开始执行,main函数的原型是: int main(int argc, char *argv[]); argc是命令行参数的数目; argv是指向参数的各个指针所构成的数组; 当内核执行C程序时,在调用main前先调用一个特殊的启动例程。可执行程序文件将此启动例程指定为程序的起始地址,由链接器设置,而链接编辑器则由C编译器调用。启动例程从内核获得命令行参数和环境变量值,然后为按上述方式调用main函数做好安排。 7.3 进程终止 有8种方式使进程终止,其中5种为正常终止,它们是: 从 main返回; 调用 exit; 调用 _Exit 或 _exit; 最后一个线程从其启动例程返回; 从最后一个线程调用 pthread_exit; 异常终止有3种,它们是: 调用 abort; 接到一个信号; 最后一个线程对取消请求做出响应; 退出函数 3个函数用于正常终止一个函数:_exit 和 _Exit立刻进入内核,exit 则先执行一些清理处理,然后返回内核。 #include <stdlib> void exit(int status); void _Exit(int status); #include <unistd.h> void _exit(int status); exit 函数总是执行一个标准 I/O库的清理关闭操作:对于所有打开流调用 fclose函数。输出缓冲中的所有数据都被冲洗。 3个推出函数都带一个整型参数,称为终止状态或退出状态,下面进程终止状态是未定义的: 调用这些函数时不带终止状态; main执行了一个无返回值 return语句; main没有声明返回类型为整型。 main函数返回一个整型值与用该值调用 exit是等价的。在main中 exit(0); 等价于 return(0);...

1 min · 109 words · Me