Skip to content

Commit

Permalink
Review
Browse files Browse the repository at this point in the history
  • Loading branch information
caipengbo committed Jul 6, 2020
1 parent e1cae8c commit 63453a9
Show file tree
Hide file tree
Showing 31 changed files with 638 additions and 89 deletions.
47 changes: 25 additions & 22 deletions src/datastructure/array/P54SpiralMatrix.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,33 @@

/**
* Title: 54. 螺旋矩阵
* Desc:
* Desc: 给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。
* Created by Myth-PC on 05/02/2020 in VSCode
*/
public class P54SpiralMatrix {

// 不使用visited数组,设置边界
public List<Integer> spiralOrder2(int[][] matrix) {
List<Integer> ret = new LinkedList<>();
if (matrix.length == 0 || matrix[0].length == 0) return ret;
int top = 0, bottom = matrix.length-1, left = 0, right = matrix[0].length-1;
int i, j;
while (left <= right && top <= bottom) {
for (j = left; j <= right; j++) ret.add(matrix[top][j]);
top++;
if (top > bottom) break;
for (i = top; i <= bottom; i++) ret.add(matrix[i][right]);
right--;
if (right < left) break;
for (j = right; j >= left; j--) ret.add(matrix[bottom][j]);
bottom--;
if (top > bottom) break;
for (i = bottom; i >= top; i--) ret.add(matrix[i][left]);
left++;
}
return ret;
}

public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> ret = new LinkedList<>();
if (matrix.length == 0 || matrix[0].length == 0) return ret;
Expand Down Expand Up @@ -66,26 +89,6 @@ public List<Integer> spiralOrder(int[][] matrix) {
return ret;
}

// 不使用visited数组,设置边界
public List<Integer> spiralOrder2(int[][] matrix) {
List<Integer> ret = new LinkedList<>();
if (matrix.length == 0 || matrix[0].length == 0) return ret;
int top = 0, bottom = matrix.length-1, left = 0, right = matrix[0].length-1;
int i, j;
while (left <= right && top <= bottom) {
for (j = left; j <= right; j++) ret.add(matrix[top][j]);
top++;
if (top > bottom) break;
for (i = top; i <= bottom; i++) ret.add(matrix[i][right]);
right--;
if (right < left) break;
for (j = right; j >= left; j--) ret.add(matrix[bottom][j]);
bottom--;
if (top > bottom) break;
for (i = bottom; i >= top; i--) ret.add(matrix[i][left]);
left++;
}
return ret;
}


}
5 changes: 3 additions & 2 deletions src/datastructure/array/P945MakeArrayUnique.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

/**
* Title: 945. 使数组唯一的最小增量
* Desc:
* Desc: 给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1。返回使 A 中的每个值都是唯一的最少操作次数。
* Created by Myth-MBP on 22/03/2020 in VSCode
*/

Expand Down Expand Up @@ -61,8 +61,9 @@ public int minIncrementForUnique3(int[] A) {
Arrays.sort(A);
int n = A.length, count = 0;
for (int i = 1; i < n; i++) {
// 这种主要是处理相等的元素
if (A[i] <= A[i-1]) {
count += A[i-1] + 1 - A[i];
count += A[i-1] + 1 - A[i]; // A[i]要变成比他自己大 1 的数字
A[i] = A[i-1] + 1;
}
}
Expand Down
10 changes: 9 additions & 1 deletion src/datastructure/hash/P1160WordCharacters.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@

/**
* Title: 1160. 拼写单词
* Desc: 如何高效的实现hash, 除了hashmap
* Desc: 给你一份『词汇表』(字符串数组) words 和一张『字母表』(字符串) chars。
假如你可以用 chars 中的『字母』(字符)拼写出 words 中的某个『单词』(字符串),那么我们就认为你掌握了这个单词。
注意:每次拼写(指拼写词汇表中的一个单词)时,chars 中的每个字母都只能用一次。
返回词汇表 words 中你掌握的所有单词的 长度之和。
*
* Created by Myth-MBP on 17/03/2020 in VSCode
*/

public class P1160WordCharacters {
// 如何高效的实现hash, 除了hashmap
public int countCharacters(String[] words, String chars) {
int n = chars.length();
Map<Character, Integer> map = new HashMap<>(n);
Expand Down
4 changes: 3 additions & 1 deletion src/datastructure/hash/P146LRUCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public void put(int key, int value) {
empty--;
}
}
// 第一步:继承LinkedHashMap
class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {

private int capacity;
Expand All @@ -104,8 +105,9 @@ protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
}
}

// 使用 LinkedHashMap
// 第二步:使用 LinkedHashMap
class LRUCache2 {
// 使用上面的LRULinkedHashMap
LRULinkedHashMap<Integer, Integer> cache;
public LRUCache2(int capacity) {
cache = new LRULinkedHashMap<>(capacity);
Expand Down
2 changes: 1 addition & 1 deletion src/datastructure/hash/P242ValidAnagram.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

/**
* Title: 242. 有效的字母异位词
* Desc:
* Desc: 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
* Created by Myth-Lab on 10/18/2019
*/
public class P242ValidAnagram {
Expand Down
12 changes: 7 additions & 5 deletions src/datastructure/hash/P41FirstMissingPositive.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ public class P41FirstMissingPositive {
// 数组长度为N,那么缺失的最小正整数一定在 [1, N+1] 之间
// 使用排序时间复杂度不符合要求,使用Hash表,空间复杂度不满足要求

// 这就需要一种类似于桶思想的 Hash方法,不使用额外的Hash表,将原数组当做Hash表进行统计
// 这就需要一种类似于桶思想的Hash方法,不使用额外的Hash表,将原数组当做Hash表进行统计
// 难点:如何将原数组当做Hash表,如何不借助额外的空间进行Hash映射

// 思路:数字nums 应该放在nums-1这个下标的位置,如何把它放过去(或者如何做标记),如何检测那些是正确归位(或者哪些没被标记)
// 思路:数字nums 应该放在nums-1这个下标的位置,如何把它放过去(或者如何做标记)
// 如何检测那些是正确归位(或者哪些没被标记)

// 方法1:放过去
public int firstMissingPositive(int[] nums) {
Expand All @@ -39,22 +40,23 @@ private void swap(int[] nums, int i, int j) {
nums[i] = nums[j];
nums[j] = temp;
}
// 方法2:做标记 (使用负号做标记)
// 方法2:做标记 (使用负号做标记)
public int firstMissingPositive2(int[] nums) {
int n = nums.length;
// 处理小于0和 > n的数(让他们都变成n+1) 如何1 —— n都出现了,那么最后肯定是n+1
for (int i = 0; i < n; i++) {
if (nums[i] < 0 || nums[i] > n) {
nums[i] = n+1;
}
}

for (int i = 0; i < n; i++) {
// 说明 i 应该放到 nums[i]-1 的位置
// 使用-1 标记 i 应该放到 nums[i]-1 的位置
if (nums[i] < n && nums[nums[i]-1] > 0) {
nums[nums[i]-1] *= -1;
}
}

// 检查
for (int i = 0; i < n; i++) {
if (nums[i] > 0) {
return i+1;
Expand Down
99 changes: 97 additions & 2 deletions src/datastructure/hash/P460LFUCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.TreeMap;
import java.util.Map.Entry;

/**
Expand All @@ -11,6 +13,98 @@
* Created by Myth-PC on 26/01/2020 in VSCode
*/

class LFUCache {
class Node {
int key;
int value;
int freq = 1;

public Node() {}

public Node(int key, int value) {
this.key = key;
this.value = value;
}
}

Map<Integer, Node> cache; // 存储缓存的内容
Map<Integer, LinkedHashSet<Node>> freqMap; // 存储每个频次对应的双向链表
int size;
int capacity;
int min; // 存储当前最小频次

public LFUCache(int capacity) {
cache = new HashMap<> (capacity);
freqMap = new HashMap<>();
this.capacity = capacity;
}

public int get(int key) {
Node node = cache.get(key);
if (node == null) {
return -1;
}
freqInc(node);
return node.value;
}

public void put(int key, int value) {
if (capacity == 0) {
return;
}
Node node = cache.get(key);
if (node != null) {
node.value = value;
freqInc(node);
} else {
if (size == capacity) {
Node deadNode = removeNode();
cache.remove(deadNode.key);
size--;
}
Node newNode = new Node(key, value);
cache.put(key, newNode);
addNode(newNode);
size++;
}
}

void freqInc(Node node) {
// 从原freq对应的链表里移除, 并更新min
int freq = node.freq;
LinkedHashSet<Node> set = freqMap.get(freq);
set.remove(node);
if (freq == min && set.size() == 0) {
min = freq + 1;
}
// 加入新freq对应的链表
node.freq++;
LinkedHashSet<Node> newSet = freqMap.get(freq + 1);
if (newSet == null) {
newSet = new LinkedHashSet<>();
freqMap.put(freq + 1, newSet);
}
newSet.add(node);
}

void addNode(Node node) {
LinkedHashSet<Node> set = freqMap.get(1);
if (set == null) {
set = new LinkedHashSet<>();
freqMap.put(1, set);
}
set.add(node);
min = 1;
}

Node removeNode() {
LinkedHashSet<Node> set = freqMap.get(min);
Node deadNode = set.iterator().next();
set.remove(deadNode);
return deadNode;
}
}
// ======= 自己实现的 有Bug=========
class LFUNode {
int key;
int val;
Expand All @@ -21,15 +115,15 @@ class LFUNode {
freq = 0;
}
}
class LFUCache {
class LFUCache2 {
HashMap<Integer, LFUNode> cache;
// freq - Set
HashMap<Integer, LinkedHashSet<LFUNode>> freqMap;

int minFrequency;

int size, capacity;
public LFUCache(int capacity) {
public LFUCache2(int capacity) {
cache = new HashMap<>();
freqMap = new HashMap<>();
minFrequency = 0;
Expand Down Expand Up @@ -84,6 +178,7 @@ private void addFreqMap(int freq, LFUNode node) {
freqMap.put(freq, newNodeSet);
}
}

public class P460LFUCache {
public static void main(String[] args) {
LFUCache cache = new LFUCache( 2 /* capacity (缓存容量) */ );
Expand Down
6 changes: 4 additions & 2 deletions src/datastructure/hash/P49GroupAnagrams.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,25 @@ public List<List<String>> groupAnagrams(String[] strs) {
}
return ret;
}

// 使用hash
public List<List<String>> groupAnagrams2(String[] strs) {
int len = strs.length;
List<List<String>> ret = new LinkedList<>();
if (len == 0) return ret;
// 类似于桶排序
int[][] strHashs = new int[len][26];
for (int i = 0; i < len; i++) {
for (int j = 0; j < strs[i].length(); j++) {
strHashs[i][strs[i].charAt(j)-'a']++;
}
}
// key代表出现过的单词
HashMap<String, List<String>> hashMap = new HashMap<>();
for (int i = 0; i < len; i++) {
// 重点 Hash的Key
StringBuilder sb = new StringBuilder("");
for (int j = 0; j < 26; j++) {
sb.append(strHashs[i][j]);
sb.append(strHashs[i][j]); // 最好加个-隔开每个单词的数目
}
String key = sb.toString();
if (hashMap.containsKey(key)) {
Expand Down
21 changes: 13 additions & 8 deletions src/datastructure/hash/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
TwoSum问题

# Hash

hash的实现,:
- 使用256数组 26数组
- HashMap
## hash的实现
- 使用256数组 26数组
- HashMap

## Cache

# Cache
Hash是无序的,所以一般需要一个双向链表来记录顺序,cache 经常使用到Hash + DoubleList

Hash是无序的,所以一般需要一个双向链表来记录顺序,cache经常使用到Hash+DoubleList
LinkedHashMap的实现就是一个LRU,其内部就是Hash+双指针

LinkedHashMap的实现就是一个LRU,其内部就是Hash+双指针
## 经典题目
- 1. TwoSum问题
- 41. 确定第一个缺失的正数
- 49. 242. 异位词(类似于桶排序)
- 146. LRU
- 460. LFU
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import java.util.Stack;

/**
* Title: 503. 下一个更大元素 II Desc: 给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。
* Title: 503. 下一个更大元素 II
* Desc: 给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。
* 数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
* Created by Myth on 01/09/2020 in VSCode
*/
Expand Down
6 changes: 4 additions & 2 deletions src/datastructure/monotonicstack/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# 单调栈可以解决的问题
# 单调栈

## 可以解决的问题
递增求更小、递减求更大

一般的问题都是:在一个序列中,可以慢慢增加(减少),在突然减少(增加)的时候,可以做一些操作
Expand All @@ -25,7 +27,7 @@

> 递减栈是下一个(前一个)更大的元素
# 模版
## 模版
单调递增栈
```Java
Stack<> stack; // 存放下标或者元素 Key1
Expand Down
Loading

0 comments on commit 63453a9

Please sign in to comment.