diff --git a/notes/剑指 offer 题解.md b/notes/剑指 offer 题解.md index 9f55503a..2da38375 100644 --- a/notes/剑指 offer 题解.md +++ b/notes/剑指 offer 题解.md @@ -525,19 +525,28 @@ public int RectCover(int n) { 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组 {3, 4, 5, 1, 2} 为 {1, 2, 3, 4, 5} 的一个旋转,该数组的最小值为 1。NOTE:给出的所有元素都大于 0,若数组大小为 0,请返回 0。 -O(N) 时间复杂度解法: +**解题思路** + +分治 + +复杂度:O(logn) + O(1),其实空间复杂度不止 O(1),因为分治使用了递归栈,用到了额外的空间,如果对空间有要求就不能用这种方法。 ```java -public int minNumberInRotateArray(int[] array) { - if (array.length == 0) return 0; - for (int i = 0; i < array.length - 1; i++) { - if (array[i] > array[i + 1]) return array[i + 1]; - } - return 0; +public int minNumberInRotateArray(int[] nums) { + return minNumberInRotateArray(nums, 0, nums.length - 1); +} + +private int minNumberInRotateArray(int[] nums, int first, int last) { + if (nums[first] < nums[last]) return nums[first]; + if (first == last) return nums[first]; + int mid = first + (last - first) / 2; + return Math.min(minNumberInRotateArray(nums, first, mid), minNumberInRotateArray(nums, mid + 1, last)); } ``` -O(lgN) 时间复杂度解法: +双指针 + +复杂度:O(logn) + O(1) ```java public int minNumberInRotateArray(int[] array) { @@ -685,7 +694,7 @@ public int NumberOf1(int n) { } ``` -**O(lgM) 时间复杂度解法,其中 M 表示 1 的个数** +**O(logM) 时间复杂度解法,其中 M 表示 1 的个数** n&(n-1) 该位运算是去除 n 的位级表示中最低的那一位。例如对于二进制表示 10110100,减去 1 得到 10110011,这两个数相与得到 10110000。 @@ -1601,7 +1610,7 @@ private boolean less(int v, int w) { **大小为 K 的最小堆** -- 时间复杂度:O(NlgK) +- 时间复杂度:O(NlogK) - 空间复杂度:O(K) - 特别适合处理海量数据 diff --git a/notes/算法.md b/notes/算法.md index bbe55ffb..f53a746e 100644 --- a/notes/算法.md +++ b/notes/算法.md @@ -97,7 +97,7 @@ 可以在其两端同时取对数,得到: -

+


@@ -177,13 +177,13 @@ public class ThreeSumFast { ## 4. 倍率实验 -如果 T(N) \~ aNblgN,那么 T(2N)/T(N) \~ 2b。 +如果 T(N) \~ aNblogN,那么 T(2N)/T(N) \~ 2b。 例如对于暴力方法的 ThreeSum 算法,近似时间为 \~N3/6。进行如下实验:多次运行该算法,每次取的 N 值为前一次的两倍,统计每次执行的时间,并统计本次运行时间与前一次运行时间的比值,得到如下结果:

-可以看到,T(2N)/T(N)\~23,因此可以确定 T(N) \~ aN2lgN。 +可以看到,T(2N)/T(N)\~23,因此可以确定 T(N) \~ aN2logN。 ## 5. 注意事项 @@ -456,7 +456,7 @@ public class UF { 为了解决 quick-union 的树通常会很高的问题,加权 quick-union 在 union 操作时会让较小的树连接较大的树上面。 -理论研究证明,加权 quick-union 算法构造的树深度最多不超过 lgN。 +理论研究证明,加权 quick-union 算法构造的树深度最多不超过 logN。

@@ -665,7 +665,7 @@ private static void sort(Comparable[] a, int lo, int hi) {

-因为每次都将问题对半分成两个子问题,而这种对半分的算法复杂度一般为 O(NlgN),因此该归并排序方法的时间复杂度也为 O(NlgN)。 +因为每次都将问题对半分成两个子问题,而这种对半分的算法复杂度一般为 O(NlogN),因此该归并排序方法的时间复杂度也为 O(NlogN)。 因为小数组的递归操作会过于频繁,因此使用插入排序来处理小数组将会获得更高的性能。 @@ -736,7 +736,7 @@ private static int partition(Comparable[] a, int lo, int hi) { 快速排序是原地排序,不需要辅助数组,但是递归调用需要辅助栈。 -快速排序最好的情况下是每次都正好能将数组对半分,这样递归调用次数才是最少的。这种情况下比较次数为 CN=2CN/2+N,也就是复杂度为 O(NlgN)。 +快速排序最好的情况下是每次都正好能将数组对半分,这样递归调用次数才是最少的。这种情况下比较次数为 CN=2CN/2+N,也就是复杂度为 O(NlogN)。 最坏的情况下,第一次从最小的元素切分,第二次从第二小的元素切分,如此这般。因此最坏的情况下需要比较 N2/2。为了防止数组最开始就是有序的,在进行快速排序时需要随机打乱数组。 @@ -894,9 +894,9 @@ public static void sort(Comparable[] a){ ### 4.6 分析 -一个堆的高度为 lgN,因此在堆中插入元素和删除最大元素的复杂度都为 lgN。 +一个堆的高度为 logN,因此在堆中插入元素和删除最大元素的复杂度都为 logN。 -对于堆排序,由于要对 N 个节点进行下沉操作,因此复杂度为 NlgN。 +对于堆排序,由于要对 N 个节点进行下沉操作,因此复杂度为 NlogN。 堆排序时一种原地排序,没有利用额外的空间。 @@ -908,7 +908,7 @@ public static void sort(Comparable[] a){

-快速排序时最快的通用排序算法,它的内循环的指令很少,而且它还能利用缓存,因为它总是顺序地访问数据。它的运行时间增长数量级为 \~cNlgN,这里的 c 比其他线性对数级别的排序算法都要小。使用三向切分之后,实际应用中可能出现的某些分布的输入能够达到线性级别,而其它排序算法仍然需要线性对数时间。 +快速排序时最快的通用排序算法,它的内循环的指令很少,而且它还能利用缓存,因为它总是顺序地访问数据。它的运行时间增长数量级为 \~cNlogN,这里的 c 比其他线性对数级别的排序算法都要小。使用三向切分之后,实际应用中可能出现的某些分布的输入能够达到线性级别,而其它排序算法仍然需要线性对数时间。 ### 5.2 Java 的排序算法实现 @@ -961,7 +961,7 @@ public static Comparable select(Comparable[] a, int k) { rank() 方法至关重要,当键在表中时,它能够知道该键的位置;当键不在表中时,它也能知道在何处插入新键。 -复杂度:二分查找最多需要 lgN+1 次比较,使用二分查找实现的符号表的查找操作所需要的时间最多是对数级别的。但是插入操作需要移动数组元素,是线性级别的。 +复杂度:二分查找最多需要 logN+1 次比较,使用二分查找实现的符号表的查找操作所需要的时间最多是对数级别的。但是插入操作需要移动数组元素,是线性级别的。 ```java public class BinarySearchST, Value> { @@ -1097,7 +1097,7 @@ private Node put(Node x, Key key, Value val) { ### 2.3 分析 -二叉查找树的算法运行时间取决于树的形状,而树的形状又取决于键被插入的先后顺序。最好的情况下树是完全平衡的,每条空链接和根节点的距离都为 lgN。在最坏的情况下,树的高度为 N。 +二叉查找树的算法运行时间取决于树的形状,而树的形状又取决于键被插入的先后顺序。最好的情况下树是完全平衡的,每条空链接和根节点的距离都为 logN。在最坏的情况下,树的高度为 N。

@@ -1393,7 +1393,7 @@ private Node put(Node x, Key key, Value val) { #### 3.2.6 分析 -一颗大小为 N 的红黑树的高度不会超过 2lgN。最坏的情况下是它所对应的 2-3 树中构成最左边的路径节点全部都是 3- 节点而其余都是 2- 节点。 +一颗大小为 N 的红黑树的高度不会超过 2logN。最坏的情况下是它所对应的 2-3 树中构成最左边的路径节点全部都是 3- 节点而其余都是 2- 节点。 红黑树大多数的操作所需要的时间都是对数级别的。