Skip to content

Commit 658798e

Browse files
committed
week08 note and homework
1 parent 214d31a commit 658798e

2 files changed

Lines changed: 616 additions & 1 deletion

File tree

Week08/NOTE.md

Lines changed: 375 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,375 @@
1-
学习笔记
1+
#### XOR异或 ^
2+
```
3+
x ^ 0 = x
4+
# 1s = ~0
5+
x ^ 1s = ~x
6+
x ^ (~x) = 1s
7+
x ^ x = 0
8+
c = a ^ b --> a ^ c = b --> b ^ c = a
9+
a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c
10+
```
11+
<br/>
12+
13+
### 指定位置的位运算
14+
```
15+
# 将x最右边的n位清零
16+
x & (~0 << n)
17+
# 获取x第n位的值(0 or 1)
18+
x >> n & 1
19+
# 获取第n位的幂值
20+
x & (1 << n)
21+
# 仅将第n位置为 1
22+
x | (1 << n)
23+
# 仅将第n位置为 0
24+
x & (~(1 << n)
25+
# 将x最高位至n位(含n)清零
26+
x & ((1 << n) - 1)
27+
# 将x第n位至0位(含n)清零
28+
x & (~((1 << n + 1) - 1))
29+
```
30+
<br/>
31+
32+
### 实战运用
33+
```
34+
# 清零最低位 1
35+
X = X & (X - 1)
36+
# 得到最低位 1
37+
X = X & -X
38+
```
39+
<br/>
40+
41+
### 布隆过滤器
42+
```
43+
# 核心:
44+
超大位数组 + hash函数
45+
46+
# 添加元素
47+
1. 将添加元素给k个hash函数
48+
2. 得到对应位数组的k个位置
49+
3. 将对应位置设为 1
50+
# 查询元素
51+
1. 将下旬元素给k个hash函数
52+
2. 得到对应位数组的k个位置
53+
3. 只要有一个位置值为 0, 则元素不存在
54+
3. 如果k个位置值全为 1, 则元素可能存在(存在误判, 用于最外层过滤)
55+
```
56+
57+
```
58+
/**
59+
* 示例代码
60+
*/
61+
public class BloomFilter {
62+
private static final int DEFAULT_SIZE = 2 << 24;
63+
private static final int[] seeds = new int[] { 5, 7, 11, 13, 31, 37, 61 };
64+
private BitSet bits = new BitSet(DEFAULT_SIZE);
65+
private SimpleHash[] func = new SimpleHash[seeds.length];
66+
public BloomFilter() {
67+
for (int i = 0; i < seeds.length; i++) {
68+
func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);
69+
}
70+
}
71+
public void add(String value) {
72+
for (SimpleHash f : func) {
73+
bits.set(f.hash(value), true);
74+
}
75+
}
76+
public boolean contains(String value) {
77+
if (value == null) {
78+
return false;
79+
}
80+
boolean ret = true;
81+
for (SimpleHash f : func) {
82+
ret = ret && bits.get(f.hash(value));
83+
}
84+
return ret;
85+
}
86+
// 内部类,simpleHash
87+
public static class SimpleHash {
88+
private int cap;
89+
private int seed;
90+
public SimpleHash(int cap, int seed) {
91+
this.cap = cap;
92+
this.seed = seed;
93+
}
94+
public int hash(String value) {
95+
int result = 0;
96+
int len = value.length();
97+
for (int i = 0; i < len; i++) {
98+
result = seed * result + value.charAt(i);
99+
}
100+
return (cap - 1) & result;
101+
}
102+
}
103+
}
104+
```
105+
<br/>
106+
107+
### LRU Cache
108+
```java
109+
/**
110+
* 示例代码
111+
*/
112+
class LRUCache {
113+
/**
114+
* 缓存映射表
115+
*/
116+
private Map<Integer, DLinkNode> cache = new HashMap<>();
117+
/**
118+
* 缓存大小
119+
*/
120+
private int size;
121+
/**
122+
* 缓存容量
123+
*/
124+
private int capacity;
125+
/**
126+
* 链表头部和尾部
127+
*/
128+
private DLinkNode head, tail;
129+
130+
public LRUCache(int capacity) {
131+
//初始化缓存大小,容量和头尾节点
132+
this.size = 0;
133+
this.capacity = capacity;
134+
head = new DLinkNode();
135+
tail = new DLinkNode();
136+
head.next = tail;
137+
tail.prev = head;
138+
}
139+
140+
/**
141+
* 获取节点
142+
* @param key 节点的键
143+
* @return 返回节点的值
144+
*/
145+
public int get(int key) {
146+
DLinkNode node = cache.get(key);
147+
if (node == null) {
148+
return -1;
149+
}
150+
//移动到链表头部
151+
(node);
152+
return node.value;
153+
}
154+
155+
/**
156+
* 添加节点
157+
* @param key 节点的键
158+
* @param value 节点的值
159+
*/
160+
public void put(int key, int value) {
161+
DLinkNode node = cache.get(key);
162+
if (node == null) {
163+
DLinkNode newNode = new DLinkNode(key, value);
164+
cache.put(key, newNode);
165+
//添加到链表头部
166+
addToHead(newNode);
167+
++size;
168+
//如果缓存已满,需要清理尾部节点
169+
if (size > capacity) {
170+
DLinkNode tail = removeTail();
171+
cache.remove(tail.key);
172+
--size;
173+
}
174+
} else {
175+
node.value = value;
176+
//移动到链表头部
177+
moveToHead(node);
178+
}
179+
}
180+
181+
/**
182+
* 删除尾结点
183+
*
184+
* @return 返回删除的节点
185+
*/
186+
private DLinkNode removeTail() {
187+
DLinkNode node = tail.prev;
188+
removeNode(node);
189+
return node;
190+
}
191+
192+
/**
193+
* 删除节点
194+
* @param node 需要删除的节点
195+
*/
196+
private void removeNode(DLinkNode node) {
197+
node.next.prev = node.prev;
198+
node.prev.next = node.next;
199+
}
200+
201+
/**
202+
* 把节点添加到链表头部
203+
*
204+
* @param node 要添加的节点
205+
*/
206+
private void addToHead(DLinkNode node) {
207+
node.prev = head;
208+
node.next = head.next;
209+
head.next.prev = node;
210+
head.next = node;
211+
}
212+
213+
/**
214+
* 把节点移动到头部
215+
* @param node 需要移动的节点
216+
*/
217+
private void moveToHead(DLinkNode node) {
218+
removeNode(node);
219+
addToHead(node);
220+
}
221+
222+
/**
223+
* 链表节点类
224+
*/
225+
private static class DLinkNode {
226+
Integer key;
227+
Integer value;
228+
DLinkNode prev;
229+
DLinkNode next;
230+
231+
DLinkNode() {
232+
}
233+
234+
DLinkNode(Integer key, Integer value) {
235+
this.key = key;
236+
this.value = value;
237+
}
238+
}
239+
}
240+
```
241+
<br/>
242+
243+
### <a href="https://www.cnblogs.com/onepixel/p/7674659.html">排序算法</a>
244+
245+
#### 冒泡排序
246+
```java
247+
public void bubbleSort(int[] nums) {
248+
int len = nums.length;
249+
// 相邻两个数比较, 顺序错误则交换位置
250+
// time:O(n ^ 2) space:O(1)
251+
for (int i = 0; i < len; i++) {
252+
for (int j = 0; j < len - 1 - i; j++) {
253+
if (nums[j] > nums[j + 1]) {
254+
int temp = nums[j];
255+
nums[j] = nums[j + 1];
256+
nums[j + 1] = temp;
257+
}
258+
}
259+
}
260+
}
261+
```
262+
<br/>
263+
264+
#### 选择排序
265+
```java
266+
public void selectionSort(int[] nums) {
267+
int len = nums.length;
268+
// 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
269+
// time:O(n ^ 2) space:O(1)
270+
for (int i = 0; i < len; i++) {
271+
int minIndex = i;
272+
for (int j = i + 1; j < len; j++) {
273+
// 找从i开始后的最小数的索引
274+
if (nums[j] < nums[minIndex]) minIndex = j;
275+
}
276+
// 交换位置
277+
int temp = nums[i];
278+
nums[i] = nums[minIndex];
279+
nums[minIndex] = temp;
280+
}
281+
}
282+
```
283+
<br/>
284+
285+
#### 插入排序
286+
```java
287+
public void selectionSort(int[] nums) {
288+
int len = nums.length;
289+
// 构建有序序列, 对于未排序数据, 在已排序序列中从后向前扫描, 找到相应位置并插入
290+
// time:O(n ^ 2) space:O(1)
291+
for (int i = 0; i < len; i++) {
292+
int curNum = nums[i], curIndex = i - 1;
293+
while (curIndex >= 0 && nums[curIndex] > curNum) {
294+
nums[curIndex + 1] = nums[curIndex];
295+
curIndex--;
296+
}
297+
nums[curIndex + 1] = curNum;
298+
}
299+
}
300+
```
301+
<br/>
302+
303+
#### 快速排序
304+
```java
305+
/**
306+
* 通过一趟排序将待排记录分隔成独立的两部分,
307+
* 其中一部分记录的关键字均比另一部分的关键字小,
308+
* 则可分别对这两部分记录继续进行排序,以达到整个序列有序
309+
*/
310+
public void quickSort(int[] nums) {
311+
// time:O(nlog n) space:O(nlog n)
312+
quickSort(nums, 0, nums.length - 1);
313+
}
314+
315+
private void quickSort(int[] nums, int begin, int end) {
316+
if (begin <= end) return;
317+
// 寻找标杆位置
318+
int pivot = partition(nums, begin, end);
319+
// pivot左边元素下探
320+
quickSort(nums, begin, pivot - 1);
321+
// pivot右边元素下探
322+
quickSort(nums, pivot + 1, end);
323+
}
324+
325+
private int partition(int[] nums, int begin, int end) {
326+
// pivot: 标杆位置, counter: 小于pivot的元素的个数
327+
int pivot = end, counter = begin;
328+
for (int i = begin; i < end; i++) {
329+
if (nums[i] < nums[pivot]) {
330+
int temp = nums[i]; nums[i] = nums[counter]; nums[counter] = temp;
331+
counter++;
332+
}
333+
}
334+
int temp = nums[pivot]; nums[pivot] = nums[counter]; nums[counter] = temp;
335+
return counter;
336+
}
337+
```
338+
<br/>
339+
340+
#### 归并排序
341+
```java
342+
/**
343+
* 采用分治法(Divide and Conquer)的一个非常典型的应用。
344+
* 将已有序的子序列合并,得到完全有序的序列;
345+
* 即先使每个子序列有序,再使子序列段间有序
346+
*/
347+
public void mergeSort(int[] nums) {
348+
// time:O(nlog n) space:O(n)
349+
mergeSort(nums, 0, nums.length - 1);
350+
}
351+
352+
private void mergeSort(int[] nums, int left, int right) {
353+
if (left <= right) return;
354+
int mid = ((right - left) >> 1) + left;
355+
// 左半部分下探
356+
mergeSort(nums, left, mid);
357+
// 右半部分下探
358+
mergeSort(nums, mid + 1, right);
359+
merge(nums, left, mid, right);
360+
}
361+
362+
/**
363+
* 合并两个有序数组
364+
*/
365+
private int merge(int[] nums, int left, int mid, int right) {
366+
int[] temp = new int[right - left + 1];
367+
int i = left, j = mid + 1, k = 0;
368+
while (i <= mid && j <= right) {
369+
temp[k++] = nums[i] < nums[j] ? nums[i++] : nums[j++];
370+
}
371+
while (i <= left) temp[k++] = nums[i++];
372+
while (j <= right) temp[k++] = nums[j++];
373+
System.arraycopy(temp, 0, nums, left, right - left + 1);
374+
}
375+
```

0 commit comments

Comments
 (0)