diff --git a/notes/算法.md b/notes/算法.md
index 0669b910..4d818bad 100644
--- a/notes/算法.md
+++ b/notes/算法.md
@@ -83,6 +83,8 @@ public class ThreeSum {
通过将数组先排序,对两个元素求和,并用二分查找方法查找是否存在该和的相反数,如果存在,就说明存在三元组的和为 0。
+应该注意的是,只有数组不含有相同元素才能使用这种解法,否则二分查找的结果会出错。
+
该方法可以将 ThreeSum 算法增长数量级降低为 O(N2logN)。
```java
@@ -94,18 +96,19 @@ public class ThreeSumFast {
for (int i = 0; i < N; i++)
for (int j = i + 1; j < N; j++) {
int target = -nums[i] - nums[j];
- int index = binarySearch(nums, target);
+ int index = BinarySearch.search(nums, target);
// 应该注意这里的下标必须大于 j,否则会重复统计。
- if (index <= j)
- continue;
- while (index < N && nums[index++] == target)
+ if (index > j)
cnt++;
}
-
return cnt;
}
+}
+```
- private static int binarySearch(int[] nums, int target) {
+```java
+public class BinarySearch {
+ public static int search(int[] nums, int target) {
int l = 0, h = nums.length - 1;
while (l <= h) {
int m = l + (h - l) / 2;
@@ -142,23 +145,38 @@ public class ThreeSumFast {
public class RatioTest {
public static void main(String[] args) {
int N = 500;
- int K = 7;
- long preTime = -1;
- while (K-- > 0) {
+ int loopTimes = 7;
+ double preTime = -1;
+ while (loopTimes-- > 0) {
int[] nums = new int[N];
- long startTime = System.currentTimeMillis();
+ StopWatch.start();
int cnt = ThreeSum.count(nums);
- long endTime = System.currentTimeMillis();
- long time = endTime - startTime;
- double ratio = preTime == -1 ? 0 : (double) time / preTime;
- System.out.println(N + " " + time + " " + ratio);
- preTime = time;
+ System.out.println(cnt);
+ double elapsedTime = StopWatch.elapsedTime();
+ double ratio = preTime == -1 ? 0 : elapsedTime / preTime;
+ System.out.println(N + " " + elapsedTime + " " + ratio);
+ preTime = elapsedTime;
N *= 2;
}
}
}
```
+```java
+public class StopWatch {
+ private static long start;
+
+ public static void start(){
+ start = System.currentTimeMillis();
+ }
+
+ public static double elapsedTime() {
+ long now = System.currentTimeMillis();
+ return (now - start) / 1000.0;
+ }
+}
+```
+
## 注意事项
### 1. 大常数
@@ -187,25 +205,39 @@ public class RatioTest {
First-In-Last-Out
+```java
+public interface MyStack- extends Iterable
- {
+ MyStack
- push(Item item);
+
+ Item pop() throws Exception;
+
+ boolean isEmpty();
+
+ int size();
+}
+```
+
### 1. 数组实现
```java
-import java.util.Iterator;
-
-public class ResizingArrayStack
- implements Iterable
- {
+public class ResizingArrayStack
- implements MyStack
- {
// 栈元素数组
private Item[] a = (Item[]) new Object[1]; // 只能通过转型来创建泛型数组
// 元素数量
private int N = 0;
- public void push(Item item) {
+ @Override
+ public MyStack
- push(Item item) {
check();
a[N++] = item;
+ return this;
}
+ @Override
public Item pop() throws Exception {
if (isEmpty())
throw new Exception("stack is empty");
+
Item item = a[--N];
check();
a[N] = null; // 避免对象游离
@@ -229,10 +261,12 @@ public class ResizingArrayStack
- implements Iterable
- {
a = tmp;
}
+ @Override
public boolean isEmpty() {
return N == 0;
}
+ @Override
public int size() {
return N;
}
@@ -240,57 +274,29 @@ public class ResizingArrayStack
- implements Iterable
- {
@Override
public Iterator
- iterator() {
// 返回逆序遍历的迭代器
- return new ReverseArrayIterator();
- }
+ return new Iterator
- () {
+ private int i = N;
- private class ReverseArrayIterator implements Iterator
- {
- private int i = N;
+ @Override
+ public boolean hasNext() {
+ return i > 0;
+ }
- @Override
- public boolean hasNext() {
- return i > 0;
- }
-
- @Override
- public Item next() {
- return a[--i];
- }
+ @Override
+ public Item next() {
+ return a[--i];
+ }
+ };
}
}
```
-```java
-public static void main(String[] args) throws Exception {
- ResizingArrayStack stack = new ResizingArrayStack();
- stack.push(1);
- stack.push(2);
- stack.push(3);
- stack.push(4);
- System.out.println(stack.isEmpty());
- System.out.println(stack.size());
- System.out.println(stack.pop());
- System.out.println(stack.pop());
- for (Integer item : stack)
- System.out.println(item);
-}
-```
-
-```html
-false
-4
-4
-3
-2
-1
-```
-
### 2. 链表实现
需要使用链表的头插法来实现,因为头插法中最后压入栈的元素在链表的开头,它的 next 指针指向前一个压入栈的元素,在弹出元素使就可以通过 next 指针遍历到前一个压入栈的元素从而让这个元素称为新的栈顶元素。
```java
-public class ListStack
- {
-
+public class ListStack
- implements MyStack
- {
private Node top = null;
private int N = 0;
@@ -299,22 +305,17 @@ public class ListStack
- {
Node next;
}
- public boolean isEmpty() {
- return N == 0;
- }
-
- public int size() {
- return N;
- }
-
- public void push(Item item) {
+ @Override
+ public MyStack
- push(Item item) {
Node newTop = new Node();
newTop.item = item;
newTop.next = top;
top = newTop;
N++;
+ return this;
}
+ @Override
public Item pop() throws Exception {
if (isEmpty())
throw new Exception("stack is empty");
@@ -323,28 +324,36 @@ public class ListStack
- {
N--;
return item;
}
-}
-```
-```java
-public static void main(String[] args) throws Exception {
- ListStack stack = new ListStack();
- stack.push(1);
- stack.push(2);
- stack.push(3);
- stack.push(4);
- System.out.println(stack.isEmpty());
- System.out.println(stack.size());
- System.out.println(stack.pop());
- System.out.println(stack.pop());
-}
-```
+ @Override
+ public boolean isEmpty() {
+ return N == 0;
+ }
-```html
-false
-4
-4
-3
+ @Override
+ public int size() {
+ return N;
+ }
+
+ @Override
+ public Iterator
- iterator() {
+ return new Iterator
- () {
+ private Node cur = top;
+
+ @Override
+ public boolean hasNext() {
+ return cur != null;
+ }
+
+ @Override
+ public Item next() {
+ Item item = cur.item;
+ cur = cur.next;
+ return item;
+ }
+ };
+ }
+}
```
## 队列
@@ -355,6 +364,88 @@ First-In-First-Out
这里需要考虑 first 和 last 指针哪个作为链表的开头。因为出队列操作需要让队首元素的下一个元素成为队首,所以需要容易获取下一个元素,而链表的头部节点的 next 指针指向下一个元素,因此可以让 first 指针链表的开头。
+```java
+public interface MyQueue
- extends Iterable
- {
+ int size();
+
+ boolean isEmpty();
+
+ MyQueue
- add(Item item);
+
+ Item remove() throws Exception;
+}
+```
+
+```java
+public class ListQueue
- implements MyQueue
- {
+ private Node first;
+ private Node last;
+ int N = 0;
+
+ private class Node {
+ Item item;
+ Node next;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return N == 0;
+ }
+
+ @Override
+ public int size() {
+ return N;
+ }
+
+ @Override
+ public MyQueue
- add(Item item) {
+ Node newNode = new Node();
+ newNode.item = item;
+ newNode.next = null;
+ if (isEmpty()) {
+ last = newNode;
+ first = newNode;
+ } else {
+ last.next = newNode;
+ last = newNode;
+ }
+ N++;
+ return this;
+ }
+
+ @Override
+ public Item remove() throws Exception {
+ if (isEmpty())
+ throw new Exception("queue is empty");
+ Node node = first;
+ first = first.next;
+ N--;
+ if (isEmpty())
+ last = null;
+ return node.item;
+ }
+
+ @Override
+ public Iterator
- iterator() {
+ return new Iterator
- () {
+ Node cur = first;
+
+ @Override
+ public boolean hasNext() {
+ return cur != null;
+ }
+
+ @Override
+ public Item next() {
+ Item item = cur.item;
+ cur = cur.next;
+ return item;
+ }
+ };
+ }
+}
+```
+
```java
public class Queue
- {
private Node first;
@@ -401,25 +492,6 @@ public class Queue
- {
}
```
-```java
-public static void main(String[] args) throws Exception {
- Queue queue = new Queue();
- queue.add(1);
- queue.add(2);
- System.out.println(queue.remove());
- System.out.println(queue.remove());
- queue.add(3);
- queue.add(4);
- System.out.println(queue.size());
-}
-```
-
-```html
-1
-2
-2
-```
-
# 三、排序
待排序的元素需要实现 Java 的 Comparable 接口,该接口有 compareTo() 方法,可以用它来判断两个元素的大小关系。