diff --git a/1 String/README.md b/1 String/README.md index f6d73e3..07353c5 100644 --- a/1 String/README.md +++ b/1 String/README.md @@ -22,6 +22,28 @@ * BM +## 滑动窗口 + + +使用滑动窗口解决字符串问题,代码框架 +``` +int left = 0, right = 0; + +while (right < s.size()) { + // 增大窗口 + window.add(s[right]); + right++; + + while (window needs shrink) { + // 缩小窗口 + window.remove(s[left]); + left++; + } +} +``` + + + ## 参考 《Algorithms》 diff --git a/4 Tree/README.md b/4 Tree/README.md index 977ba8a..7837139 100644 --- a/4 Tree/README.md +++ b/4 Tree/README.md @@ -18,6 +18,10 @@ ## [二叉查找树](2-二叉查找树/二叉查找树.md) +快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历 + + + ## [AVL树](3-平衡树AVL/README.md) diff --git a/6 Sort/README.md b/6 Sort/README.md index 91f1b50..6c48a16 100644 --- a/6 Sort/README.md +++ b/6 Sort/README.md @@ -18,7 +18,7 @@ * 桶排序 -## 交换排序算法 +# 交换排序算法 排序算法的复杂度由 `比较的次数` 和 `交换的次数` 一起决定。 @@ -77,14 +77,18 @@ 递归一次,pivot 左边都比它小,右边都比它大。这是递归,分治的思想。 +> 快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历 + 对 A[p...r] : -1. 分解:A[p..q-1] A[q+1..r],使得 A[p...q-1]=tmp){ + while(i=tmp){ j--; } if (i1) - { - merge_sort(a,length/2); - merge_sort(a+length/2,length-length/2); - merge_array(a,length/2,a+length/2,length-length/2); - } +归并排序的代码框架如下: + +``` +void sort(int[] nums, int lo, int hi) { + int mid = (lo + hi) / 2; + sort(nums, lo, mid); + sort(nums, mid + 1, hi); + + /****** 后序遍历位置 ******/ + // 合并两个排好序的子数组 + merge(nums, lo, mid, hi); + /************************/ +} +``` @@ -239,7 +253,7 @@ 国外也有人通过舞蹈的方式编排了几种基本的排序算法,非常有趣。[点这里去看看](http://v.youku.com/v_show/id_XMzMyODk4NTQ4.html?from=s1.8-1-1.2) -## 线性排序算法 +# 线性排序算法 上面的算法都是基于比较的排序,时间复杂度最好也是 NlogN.而非基于比较的排序,可以突破NlogN的时间下限。当然,非比较的排序,也是需要有一些限定条件的。 @@ -252,7 +266,7 @@ -### 小结 +# 小结 常见的排序算法都是比较排序,比较排序的时间复杂度通常为 O(n^2) 或 O(nlogn) 但是如果带排序的数字有一些特俗性时,我们可以根据这来设计更加优化的排序算法。 diff --git a/9 Algorithms Job Interview/1.1 字符串-查找.md b/9 Algorithms Job Interview/1.1 字符串-查找.md index e9eb47d..b8f1057 100644 --- a/9 Algorithms Job Interview/1.1 字符串-查找.md +++ b/9 Algorithms Job Interview/1.1 字符串-查找.md @@ -123,6 +123,45 @@ int longest_continuious_number(const char *input,char *output){ ``` + +## 最长无重复子串问题 + +给一个字符串,找出不包含有重复字符的最长子串的长度 +如 ”abcabbcbb“ 输出 3 + +思路1: 两个指针 +思路2: 窗口函数 + + +两个指针窗口函数实现 + +``` +int lengthOfLongestSubstring(string s) { + unordered_map window; + + int left = 0, right = 0; + int res = 0; // 记录结果 + while (right < s.size()) { + char c = s[right]; + right++; + // 进行窗口内数据的一系列更新 + window[c]++; + // 判断左侧窗口是否要收缩 + while (window[c] > 1) { + char d = s[left]; + left++; + // 进行窗口内数据的一系列更新 + window[d]--; + } + // 在这里更新答案 + res = max(res, right - left); + } + return res; +} +``` + + + ## 求最大连续递增数字子串 如“ads3sl456789DF3456ld345AA”中的“456789”就是所求。这道题在上一道题目的基础上增加了数字要递增的条件。思路跟上面差不多,碰到不递增的数字就相当于第二个数字串了。 @@ -152,7 +191,6 @@ int longest_common_subsequence(const char *s1,const char *s2, char *common){ ``` - ## 对称子字符串的最大长度 题目:输入一个字符串,输出该字符串中对称的子字符串的最大长度。比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。 diff --git a/9 Algorithms Job Interview/1.3 字符串-修改.md b/9 Algorithms Job Interview/1.3 字符串-修改.md index 40ccc9e..2eeaef0 100644 --- a/9 Algorithms Job Interview/1.3 字符串-修改.md +++ b/9 Algorithms Job Interview/1.3 字符串-修改.md @@ -2,8 +2,6 @@ - - ## 翻转句子中单词的顺序 题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。 @@ -190,8 +188,6 @@ char *proc(char *str){ - - ## 字符串原地压缩 题目描述:“abeeeeegaaaffa" 压缩为 "abe5ag3f2a",请编程实现。 diff --git a/9 Algorithms Job Interview/5.3 数列-交并集.md b/9 Algorithms Job Interview/5.3 数列-交并集.md index 7eb6c53..d7a9698 100644 --- a/9 Algorithms Job Interview/5.3 数列-交并集.md +++ b/9 Algorithms Job Interview/5.3 数列-交并集.md @@ -24,7 +24,7 @@ B = [1,2,7] A = [1,2,4,5,6,7] ``` -思路1: +思路1:合并2个数列,变成 `[4,5,6,1,2,7]` , 归因排序即可 思路2: diff --git a/9 Algorithms Job Interview/7 二叉树.md b/9 Algorithms Job Interview/7 二叉树.md index a7fba16..2725751 100644 --- a/9 Algorithms Job Interview/7 二叉树.md +++ b/9 Algorithms Job Interview/7 二叉树.md @@ -7,6 +7,9 @@ * 子树 +写二叉树的算法题,都是基于递归框架的。我们先要搞清楚 root 节点它自己要做什么,然后根据题目要求选择使用前序,中序,后续的递归框架。 + + 二元树的结点定义如下: ``` struct SBinaryTreeNode // a node of the binary tree @@ -19,8 +22,56 @@ struct SBinaryTreeNode // a node of the binary tree +## 二叉树翻转 + +输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点。用递归和循环两种方法完成树的镜像转换。例 + +如输入: +``` + 8 + / \ + 6 10 + /\ / \ +5 7 9 11 +``` +输出: + +``` + 8 + / \ + 10 6 + /\ /\ +11 9 7 5 +``` + +思路:二叉树翻转 , 把二叉树上的每一个节点的左右子节点进行交换 + +``` +// 将整棵树的节点翻转 +TreeNode invertTree(TreeNode root) { + // base case + if (root == null) { + return null; + } + + /**** 前序遍历位置 ****/ + // root 节点需要交换它的左右子节点 + TreeNode tmp = root.left; + root.left = root.right; + root.right = tmp; + + // 让左右子节点继续翻转它们的子节点 + invertTree(root.left); + invertTree(root.right); + + return root; +} +``` + + ## 把二元查找树转变成排序的双向链表 +难度:中等 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求`不能创建任何新的结点`,只调整指针的指向。 ``` @@ -40,6 +91,27 @@ struct SBinaryTreeNode // a node of the binary tree + + +## 二叉树两个结点的最低共同父结点 + +设计一个算法,找出二叉树上任意两个结点的最近共同父结点。复杂度如果是O(n2)则不得分 + + +输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。 + +分析:求数中两个结点的最低共同结点是面试中经常出现的一个问题。这个问题至少有两个变种。 + + + +## 求一个二叉树中任意两个节点间的最大距离 + +两个节点的距离的定义是 这两个节点间边的个数,比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复杂度。 + + + + + ## 在二元树中找出和为某一值的所有路径 题目:输入一个整数和一棵二元树。从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。打印出和与输入整数相等的所有路径。 @@ -65,47 +137,4 @@ struct SBinaryTreeNode // a node of the binary tree -## 二叉树翻转 - -输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点。用递归和循环两种方法完成树的镜像转换。例 - -如输入: -``` - 8 - / \ - 6 10 - /\ / \ -5 7 9 11 -``` -输出: - -``` - 8 - / \ - 10 6 - /\ /\ -11 9 7 5 -``` - - - -## 二叉树两个结点的最低共同父结点 - -设计一个算法,找出二叉树上任意两个结点的最近共同父结点。复杂度如果是O(n2)则不得分 - - -输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。 - -分析:求数中两个结点的最低共同结点是面试中经常出现的一个问题。这个问题至少有两个变种。 - - - -## 求一个二叉树中任意两个节点间的最大距离 - -两个节点的距离的定义是 这两个节点间边的个数,比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复杂度。 - - - - - diff --git a/9 Algorithms Job Interview/7.1 二叉树-遍历.md b/9 Algorithms Job Interview/7.1 二叉树-遍历.md index 376ceab..f072186 100644 --- a/9 Algorithms Job Interview/7.1 二叉树-遍历.md +++ b/9 Algorithms Job Interview/7.1 二叉树-遍历.md @@ -1,9 +1,10 @@ # 二叉树-遍历 +> 快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历 -## 俩种方法实现二叉树的前序遍历。 +## 2种方法实现二叉树的前序遍历。 递归和非递归