commit
9e8e091286
6
.gitignore
vendored
6
.gitignore
vendored
@ -44,4 +44,8 @@ bld/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
.vs/
|
||||
|
||||
**/*.idea
|
||||
**/*.iml
|
||||
**/*out
|
||||
|
136
DynamicStackBaseArray.java
Normal file
136
DynamicStackBaseArray.java
Normal file
@ -0,0 +1,136 @@
|
||||
package Stack;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* 顺序栈的动态扩容
|
||||
* Author: PeiJiaNi
|
||||
* @param <T> 顺序栈元素类型
|
||||
*/
|
||||
|
||||
public class DynamicStackBaseArray<T> implements Iterable<T> {
|
||||
private T[] items; // 数组
|
||||
private int count; // 栈中的元素个数
|
||||
private int length; // 栈空间大小
|
||||
|
||||
/**
|
||||
* 初始化栈
|
||||
*
|
||||
* @param length 栈空间大小
|
||||
*/
|
||||
public DynamicStackBaseArray(int length) {
|
||||
this.items = (T[]) new Object[length];
|
||||
this.count = 0;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入栈操作 平均时间复杂度O(1)
|
||||
*
|
||||
* @param item 入栈元素
|
||||
*/
|
||||
public void push(T item) {
|
||||
// 栈空间已满,则扩容
|
||||
if (count == length) {
|
||||
resize(2 * items.length);
|
||||
}
|
||||
|
||||
items[count++] = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 出栈操作 平均时间复杂度O(1)
|
||||
*
|
||||
* @return 如果栈内不为空,则返回栈顶元素,否则返回-1
|
||||
*/
|
||||
public T pop() {
|
||||
if (count == 0) {
|
||||
System.out.println("当前栈已空,无法进行出栈操作");
|
||||
return null;
|
||||
}
|
||||
|
||||
T item = items[--count];
|
||||
items[count] = null;
|
||||
|
||||
if (count > 0 && (count == items.length / 4)) {
|
||||
resize(items.length / 2);
|
||||
}
|
||||
|
||||
// 返回下标为 count-1 的数组元素,并且栈中元素个数count-1
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 栈空间动态增加或减小
|
||||
*
|
||||
* @param size
|
||||
*/
|
||||
private void resize(int size) {
|
||||
T[] newItems = (T[]) new Object[size];
|
||||
for (int i = 0; i < count; i++) {
|
||||
newItems[i] = this.items[i];
|
||||
}
|
||||
this.items = newItems;
|
||||
}
|
||||
|
||||
//返回栈中最近添加的元素而不删除它
|
||||
public T peek() {
|
||||
return items[count - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前栈是否为空
|
||||
*
|
||||
* @return 栈为空,则返回true,否则返回-1
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回栈中元素个数
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int size() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new ArrayIterator();
|
||||
}
|
||||
|
||||
// 内部类
|
||||
class ArrayIterator implements Iterator {
|
||||
int numOfItems = count;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return numOfItems > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return items[--numOfItems];
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
DynamicStackBaseArray<Integer> stack = new DynamicStackBaseArray<Integer>(6);
|
||||
stack.push(1);
|
||||
stack.push(2);
|
||||
stack.push(3);
|
||||
stack.push(4);
|
||||
stack.push(5);
|
||||
// System.out.println(stack.peek());
|
||||
Iterator iterator = stack.iterator();
|
||||
// System.out.println(iterator.hasNext());
|
||||
while (iterator.hasNext()) {
|
||||
System.out.println(iterator.next());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
# 数据结构和算法必知必会的50个代码实现
|
||||
## (关注“小争哥”公众号,获取我的更多技术、非技术分享)
|
||||
### 微信搜索我的公众号“小争哥”,或者微信扫描下面二维码, 获取更多压箱底的干货分享
|
||||
|
||||
![t2](https://github.com/wangzheng0822/markdownphotos/blob/master/pics/qrcode_for_gh_9b0e7afdff20_258.jpg)
|
||||
|
||||
## 数组
|
||||
* 实现一个支持动态扩容的数组
|
||||
|
64
StackBaseArray.java
Normal file
64
StackBaseArray.java
Normal file
@ -0,0 +1,64 @@
|
||||
package Stack;
|
||||
|
||||
/**
|
||||
* 顺序栈(基于数组实现)
|
||||
* Author: PeiJiaNi
|
||||
*/
|
||||
public class StackBaseArray {
|
||||
private int[] items; // 数组
|
||||
private int count; // 栈中元素个数
|
||||
private int length; // 栈空间大小
|
||||
|
||||
public StackBaseArray(int capactiy) {
|
||||
this.items = new int[capactiy];
|
||||
this.count = 0;
|
||||
this.length = capactiy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入栈操作 时间复杂度O(1)
|
||||
* @param item 要入栈的元素
|
||||
* @return 入栈成功则返回true,否则返回false
|
||||
*/
|
||||
public boolean push(int item) {
|
||||
if(count == length) {
|
||||
System.out.println("当前栈已满,无法进行入栈操作");
|
||||
return false;
|
||||
}
|
||||
items[count] = item;
|
||||
++count;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 出栈操作 时间复杂度O(1)
|
||||
* @return 如果栈内不为空,则返回栈顶元素,否则返回-1
|
||||
*/
|
||||
public int pop(){
|
||||
if(count == 0) {
|
||||
System.out.println("当前栈已空,无法进行出栈操作");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 返回下标为 count-1 的数组元素,并且栈中元素个数count-1
|
||||
return items[--count];
|
||||
}
|
||||
|
||||
public static void main(String[] args){
|
||||
StackBaseArray stack = new StackBaseArray(6);
|
||||
stack.push(1);
|
||||
stack.push(2);
|
||||
stack.push(3);
|
||||
stack.push(4);
|
||||
stack.push(5);
|
||||
System.out.println(stack.pop());
|
||||
System.out.println(stack.pop());
|
||||
System.out.println(stack.pop());
|
||||
System.out.println(stack.pop());
|
||||
System.out.println(stack.pop());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ int delete(struct array *array, int idx)
|
||||
return -1;
|
||||
|
||||
memmove(&array->arr[idx], &array->arr[idx+1],
|
||||
(array->used - idx) * sizeof(int));
|
||||
(array->used - idx - 1) * sizeof(int));
|
||||
array->used--;
|
||||
return 0;
|
||||
}
|
||||
|
22
go/29_priority_queue/heap.go
Normal file
22
go/29_priority_queue/heap.go
Normal file
@ -0,0 +1,22 @@
|
||||
package pqueue
|
||||
|
||||
func adjustHeap(src []Node, start, end int) {
|
||||
if start >= end {
|
||||
return
|
||||
}
|
||||
|
||||
// 只需要保证优先级最高的节点在 src[1] 的位置即可
|
||||
for i := end / 2; i >= start; i-- {
|
||||
high := i
|
||||
if src[high].priority < src[2*i].priority {
|
||||
high = 2 * i
|
||||
}
|
||||
if 2*i+1 <= end && src[high].priority < src[2*i+1].priority {
|
||||
high = 2*i + 1
|
||||
}
|
||||
if high == i {
|
||||
continue
|
||||
}
|
||||
src[high], src[i] = src[i], src[high]
|
||||
}
|
||||
}
|
14
go/29_priority_queue/heap_test.go
Normal file
14
go/29_priority_queue/heap_test.go
Normal file
@ -0,0 +1,14 @@
|
||||
package pqueue
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_AdjustHeap(t *testing.T) {
|
||||
list := []Node{Node{0, 0}, Node{1, 1}, Node{2, 2}, Node{3, 3}, Node{4, 1}, Node{6, 6}}
|
||||
|
||||
adjustHeap(list, 1, len(list)-1)
|
||||
assert.Equal(t, 6, list[1].value)
|
||||
}
|
62
go/29_priority_queue/priority_queue.go
Normal file
62
go/29_priority_queue/priority_queue.go
Normal file
@ -0,0 +1,62 @@
|
||||
package pqueue
|
||||
|
||||
// Node 队列节点
|
||||
type Node struct {
|
||||
value int
|
||||
priority int
|
||||
}
|
||||
|
||||
// PQueue priority queue
|
||||
type PQueue struct {
|
||||
heap []Node
|
||||
|
||||
capacity int
|
||||
used int
|
||||
}
|
||||
|
||||
// NewPriorityQueue new
|
||||
func NewPriorityQueue(capacity int) PQueue {
|
||||
return PQueue{
|
||||
heap: make([]Node, capacity+1, capacity+1),
|
||||
capacity: capacity,
|
||||
used: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Push 入队
|
||||
func (q *PQueue) Push(node Node) {
|
||||
|
||||
if q.used > q.capacity {
|
||||
// 队列已满
|
||||
return
|
||||
}
|
||||
q.used++
|
||||
q.heap[q.used] = node
|
||||
// 堆化可以放在 Pop 中
|
||||
// adjustHeap(q.heap, 1, q.used)
|
||||
}
|
||||
|
||||
// Pop 出队列
|
||||
func (q *PQueue) Pop() Node {
|
||||
if q.used == 0 {
|
||||
return Node{-1, -1}
|
||||
}
|
||||
// 先堆化, 再取堆顶元素
|
||||
adjustHeap(q.heap, 1, q.used)
|
||||
node := q.heap[1]
|
||||
|
||||
q.heap[1] = q.heap[q.used]
|
||||
q.used--
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
// Top 获取队列顶部元素
|
||||
func (q *PQueue) Top() Node {
|
||||
if q.used == 0 {
|
||||
return Node{-1, -1}
|
||||
}
|
||||
|
||||
adjustHeap(q.heap, 1, q.used)
|
||||
return q.heap[1]
|
||||
}
|
74
go/29_priority_queue/priority_queue_test.go
Normal file
74
go/29_priority_queue/priority_queue_test.go
Normal file
@ -0,0 +1,74 @@
|
||||
package pqueue
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Push(t *testing.T) {
|
||||
queue := NewPriorityQueue(100)
|
||||
|
||||
queue.Push(Node{0, 1})
|
||||
assert.Equal(t, 0, queue.Top().value)
|
||||
|
||||
queue.Push(Node{3, 1})
|
||||
assert.Equal(t, 0, queue.Top().value)
|
||||
|
||||
queue.Push(Node{3, 2})
|
||||
assert.Equal(t, 3, queue.Top().value)
|
||||
|
||||
queue.Push(Node{6, 6})
|
||||
assert.Equal(t, 6, queue.Top().value)
|
||||
|
||||
queue.Push(Node{12, 5})
|
||||
assert.Equal(t, 6, queue.Top().value)
|
||||
|
||||
queue.Push(Node{13, 8})
|
||||
assert.Equal(t, 13, queue.Top().value)
|
||||
}
|
||||
|
||||
func Test_PushPop(t *testing.T) {
|
||||
queue := NewPriorityQueue(100)
|
||||
|
||||
queue.Push(Node{0, 1})
|
||||
queue.Push(Node{3, 1})
|
||||
queue.Push(Node{3, 2})
|
||||
queue.Push(Node{6, 6})
|
||||
queue.Push(Node{12, 5})
|
||||
queue.Push(Node{13, 8})
|
||||
assert.Equal(t, 13, queue.Top().value)
|
||||
|
||||
assert.Equal(t, 13, queue.Pop().value)
|
||||
assert.Equal(t, 6, queue.Pop().value)
|
||||
assert.Equal(t, 12, queue.Top().value)
|
||||
assert.Equal(t, 12, queue.Pop().value)
|
||||
|
||||
queue.Push(Node{24, 8})
|
||||
assert.Equal(t, 24, queue.Top().value)
|
||||
}
|
||||
|
||||
// 无法保证入队顺序和出队顺序的一致性
|
||||
// func Test_PushPop_Equal(t *testing.T) {
|
||||
// queue := NewPriorityQueue(9)
|
||||
|
||||
// queue.Push(Node{0, 1}) // 8
|
||||
// queue.Push(Node{3, 1}) // 9
|
||||
// queue.Push(Node{3, 2}) // 3
|
||||
// queue.Push(Node{6, 2}) // 4
|
||||
// queue.Push(Node{11, 3}) // 2
|
||||
// queue.Push(Node{12, 2}) // 5
|
||||
// queue.Push(Node{13, 2}) // 6
|
||||
// queue.Push(Node{19, 5}) // 1
|
||||
// queue.Push(Node{17, 2}) // 7
|
||||
|
||||
// assert.Equal(t, 19, queue.Pop().value)
|
||||
// assert.Equal(t, 11, queue.Pop().value)
|
||||
// assert.Equal(t, 3, queue.Pop().value)
|
||||
// assert.Equal(t, 6, queue.Pop().value)
|
||||
// assert.Equal(t, 12, queue.Pop().value)
|
||||
// assert.Equal(t, 13, queue.Pop().value)
|
||||
// assert.Equal(t, 17, queue.Pop().value)
|
||||
// assert.Equal(t, 0, queue.Pop().value)
|
||||
// assert.Equal(t, 3, queue.Pop().value)
|
||||
// }
|
3
go/29_priority_queue/readme.md
Normal file
3
go/29_priority_queue/readme.md
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
## TODO
|
||||
- 该实现方式不能保证 相同优先级的元素在出队列时 和入队列的顺序是一致的
|
42
go/42_dynamic_programming/longest_common_substring.go
Normal file
42
go/42_dynamic_programming/longest_common_substring.go
Normal file
@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func lsc(s1 string, s2 string) int {
|
||||
m := len(s1)
|
||||
n := len(s2)
|
||||
|
||||
memo := make([][]int, m + 1)
|
||||
for i := 0; i < m + 1; i++ {
|
||||
memo[i] = make([]int, n + 1)
|
||||
}
|
||||
|
||||
|
||||
for i := 1; i < m + 1; i++ {
|
||||
for j := 1; j < n + 1; j++ {
|
||||
if s1[i - 1] == s2[j - 1] {
|
||||
memo[i][j] = memo[i - 1][j - 1] + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(memo)
|
||||
longest := 0
|
||||
for i, _ := range memo {
|
||||
for j, e2 := range memo[i] {
|
||||
if longest < memo[i][j] {
|
||||
longest = e2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return longest
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(lsc("blue", "clues")) //3
|
||||
fmt.Println(lsc("fosh", "fish")) //2
|
||||
fmt.Println(lsc("fosh", "fort")) //2
|
||||
fmt.Println(lsc("hish", "fish")) //3
|
||||
fmt.Println(lsc("hish", "vista")) //2
|
||||
}
|
@ -13,21 +13,14 @@ public class LinkedListAlgo {
|
||||
|
||||
// 单链表反转
|
||||
public static Node reverse(Node list) {
|
||||
Node headNode = null;
|
||||
|
||||
Node previousNode = null;
|
||||
Node currentNode = list;
|
||||
while (currentNode != null) {
|
||||
Node nextNode = currentNode.next;
|
||||
if (nextNode == null) {
|
||||
headNode = currentNode;
|
||||
}
|
||||
currentNode.next = previousNode;
|
||||
previousNode = currentNode;
|
||||
currentNode = nextNode;
|
||||
Node curr = list, pre = null;
|
||||
while (curr != null) {
|
||||
Node next = curr.next;
|
||||
curr.next = pre;
|
||||
pre = curr;
|
||||
curr = next;
|
||||
}
|
||||
|
||||
return headNode;
|
||||
return pre;
|
||||
}
|
||||
|
||||
// 检测环
|
||||
|
@ -5,7 +5,7 @@ package stack;
|
||||
*
|
||||
* Author: Zheng
|
||||
*/
|
||||
public class StackBasedLinkedList {
|
||||
public class StackBasedOnLinkedList {
|
||||
private Node top = null;
|
||||
|
||||
public void push(int value) {
|
||||
|
@ -27,8 +27,9 @@ public class KthSmallest {
|
||||
int pivot = arr[r];
|
||||
|
||||
int i = p;
|
||||
for (int j = p; j <= r - 1; j++) {
|
||||
if (arr[j] < pivot) {
|
||||
for (int j = p; j < r; j++) {
|
||||
// 这里要是 <= ,不然会出现死循环,比如查找数组 [1,1,2] 的第二小的元素
|
||||
if (arr[j] <= pivot) {
|
||||
swap(arr, i, j);
|
||||
i++;
|
||||
}
|
||||
|
131
java/36_ac_automata/ACAutoMata.java
Normal file
131
java/36_ac_automata/ACAutoMata.java
Normal file
@ -0,0 +1,131 @@
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author wayne
|
||||
*/
|
||||
public class ACAutoMata {
|
||||
private ACNode root;
|
||||
|
||||
public ACAutoMata() {
|
||||
this.root = new ACNode("/");
|
||||
}
|
||||
|
||||
private void insert (String pattern) {
|
||||
ACNode node = this.root;
|
||||
int len = pattern.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
String c = pattern.charAt(i) + "";
|
||||
if(Objects.isNull(node.children.get(c))) {
|
||||
node.children.put(c, new ACNode(c));
|
||||
}
|
||||
node = node.children.get(c);
|
||||
}
|
||||
|
||||
node.isEndingChar = true;
|
||||
node.length = pattern.length();
|
||||
}
|
||||
|
||||
private void buildFailurePointer() {
|
||||
ACNode root = this.root;
|
||||
LinkedList<ACNode> queue = new LinkedList<>();
|
||||
queue.add(root);
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
ACNode p = queue.pop();
|
||||
|
||||
for(ACNode pc: p.children.values()){
|
||||
if (Objects.isNull(pc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(p == root) {
|
||||
pc.fail = root;
|
||||
} else {
|
||||
ACNode q = p.fail;
|
||||
while (Objects.nonNull(q)) {
|
||||
ACNode qc = q.children.get(pc.data);
|
||||
if(Objects.nonNull(qc)) {
|
||||
pc.fail = qc;
|
||||
break;
|
||||
}
|
||||
q = q.fail;
|
||||
}
|
||||
if(Objects.isNull(q)) {
|
||||
pc.fail = root;
|
||||
}
|
||||
}
|
||||
queue.add(pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean match (String text) {
|
||||
ACNode root = this.root;
|
||||
ACNode p = root;
|
||||
|
||||
int n = text.length();
|
||||
for(int i = 0; i < n; i++) {
|
||||
String c = text.charAt(i) + "";
|
||||
while(Objects.isNull(p.children.get(c)) && p != root){
|
||||
p = p.fail;
|
||||
}
|
||||
|
||||
p = p.children.get(c);
|
||||
if(Objects.isNull(p)) {
|
||||
p = root;
|
||||
}
|
||||
|
||||
ACNode tmp = p;
|
||||
while ( tmp != root) {
|
||||
if (tmp.isEndingChar == true) {
|
||||
System.out.println("Start from " + (i - p.length + 1));
|
||||
return true;
|
||||
}
|
||||
tmp = tmp.fail;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean match(String text, String[] patterns) {
|
||||
ACAutoMata automata = new ACAutoMata();
|
||||
for (String pattern: patterns) {
|
||||
automata.insert(pattern);
|
||||
}
|
||||
|
||||
automata.buildFailurePointer();
|
||||
return automata.match(text);
|
||||
}
|
||||
|
||||
public class ACNode {
|
||||
private String data;
|
||||
private Map<String, ACNode> children;
|
||||
private Boolean isEndingChar;
|
||||
private Integer length;
|
||||
private ACNode fail;
|
||||
|
||||
public ACNode(String data) {
|
||||
this.data = data;
|
||||
this.children = new HashMap<>();
|
||||
this.isEndingChar = false;
|
||||
this.length = 0;
|
||||
this.fail = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String[] patterns = {"at", "art", "oars", "soar"};
|
||||
String text = "soarsoars";
|
||||
System.out.println(match(text, patterns));
|
||||
|
||||
String[] patterns2 = {"Fxtec Pro1", "谷歌Pixel"};
|
||||
|
||||
String text2 = "一家总部位于伦敦的公司Fxtex在MWC上就推出了一款名为Fxtec Pro1的手机,该机最大的亮点就是采用了侧滑式全键盘设计。DxOMark年度总榜发布 华为P20 Pro/谷歌Pixel 3争冠";
|
||||
System.out.println(match(text2, patterns2));
|
||||
}
|
||||
}
|
@ -86,7 +86,7 @@ LList.insert('curry', 'chen')
|
||||
LList.insert('sang', 'head')
|
||||
LList.insert('zhao', 'head')
|
||||
console.log('-------------remove item------------')
|
||||
LList.remove('curry', 'chen')
|
||||
LList.remove('curry')
|
||||
LList.display()
|
||||
console.log('-------------find by item------------')
|
||||
LList.findByValue('chen')
|
||||
|
40
javascript/12_sorts/KthNum.js
Normal file
40
javascript/12_sorts/KthNum.js
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 第k大的数
|
||||
* @param {array} arr
|
||||
* @param {number} k
|
||||
*/
|
||||
function kthNum(arr, k) {
|
||||
const len = arr.length;
|
||||
if (k > len) {
|
||||
return -1;
|
||||
}
|
||||
let p = partition(arr, 0, len - 1);
|
||||
while (p + 1 !== k) {
|
||||
if (p + 1 > k) {
|
||||
p = partition(arr, 0, p - 1);
|
||||
} else {
|
||||
p = partition(arr, p + 1, len - 1);
|
||||
}
|
||||
}
|
||||
return arr[p];
|
||||
}
|
||||
|
||||
function partition(arr, start, end) {
|
||||
let i = start;
|
||||
let pivot = arr[end];
|
||||
for (let j = start; j < end; j++) {
|
||||
if (arr[j] > pivot) {
|
||||
swap(arr, i, j);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
swap(arr, i, end);
|
||||
return i;
|
||||
}
|
||||
|
||||
function swap(arr, i, j) {
|
||||
if (i === j) return;
|
||||
let tmp = arr[i];
|
||||
arr[i] = arr[j];
|
||||
arr[j] = tmp;
|
||||
}
|
109
javascript/36_ac_automata/ac_automata_unicode.js
Normal file
109
javascript/36_ac_automata/ac_automata_unicode.js
Normal file
@ -0,0 +1,109 @@
|
||||
|
||||
class ACNode {
|
||||
constructor(data){
|
||||
this.data = data;
|
||||
this.children = new Map();
|
||||
this.isEndingChar = false;
|
||||
this.length = 0;
|
||||
this.fail = null;
|
||||
}
|
||||
}
|
||||
|
||||
class ACTree {
|
||||
|
||||
constructor(data){
|
||||
this.root = new ACNode('/')
|
||||
}
|
||||
|
||||
insert (text) {
|
||||
let node = this.root;
|
||||
for (let char of text) {
|
||||
if(!node.children.get(char)) {
|
||||
node.children.set(char, new ACNode(char));
|
||||
}
|
||||
node = node.children.get(char);
|
||||
}
|
||||
|
||||
node.isEndingChar = true;
|
||||
node.length = text.length;
|
||||
}
|
||||
|
||||
buildFailurePointer() {
|
||||
let root = this.root;
|
||||
let queue = [];
|
||||
queue.push(root);
|
||||
|
||||
while (queue.length > 0) {
|
||||
let p = queue.shift();
|
||||
|
||||
for(var pc of p.children.values()){
|
||||
if (!pc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(p == root) {
|
||||
pc.fail = root;
|
||||
} else {
|
||||
let q = p.fail;
|
||||
while (q) {
|
||||
let qc = q.children.get(pc.data);
|
||||
if(qc) {
|
||||
pc.fail = qc;
|
||||
break;
|
||||
}
|
||||
q = q.fail;
|
||||
}
|
||||
if(!q) {
|
||||
pc.fail = root;
|
||||
}
|
||||
}
|
||||
queue.push(pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match (text) {
|
||||
let root = this.root;
|
||||
let n = text.length;
|
||||
let p = root;
|
||||
|
||||
for(let i = 0; i < n; i++) {
|
||||
let char = text[i];
|
||||
while(!p.children.get(char) && p != root){
|
||||
p = p.fail;
|
||||
}
|
||||
|
||||
p = p.children.get(char);
|
||||
if(!p) {
|
||||
p = root;
|
||||
}
|
||||
|
||||
let tmp = p;
|
||||
while ( tmp != root) {
|
||||
if (tmp.isEndingChar == true) {
|
||||
console.log(`Start from ${i - p.length + 1}, length: ${p.length}`);
|
||||
}
|
||||
tmp = tmp.fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function match( text, patterns) {
|
||||
let automata = new ACTree();
|
||||
for (let pattern of patterns) {
|
||||
automata.insert(pattern);
|
||||
}
|
||||
|
||||
automata.buildFailurePointer();
|
||||
automata.match(text);
|
||||
}
|
||||
|
||||
let patterns = ["at", "art", "oars", "soar"];
|
||||
let text = "soarsoars";
|
||||
match(text, patterns);
|
||||
|
||||
let patterns2 = ["Fxtec Pro1", "谷歌Pixel"];
|
||||
let text2 = "一家总部位于伦敦的公司Fxtex在MWC上就推出了一款名为Fxtec Pro1的手机,该机最大的亮点就是采用了侧滑式全键盘设计。DxOMark年度总榜发布 华为P20 Pro/谷歌Pixel 3争冠";
|
||||
match(text2, patterns2);
|
||||
|
91
javascript/43_topological_sorting/dsf.js
Normal file
91
javascript/43_topological_sorting/dsf.js
Normal file
@ -0,0 +1,91 @@
|
||||
|
||||
function Graph() {
|
||||
var graph = {
|
||||
adj: new Map(),
|
||||
addEdge: function (from, to){
|
||||
if(!this.adj.get(from)) {
|
||||
this.adj.set(from, [ to ]);
|
||||
} else {
|
||||
this.adj.get(from).push(to);
|
||||
}
|
||||
},
|
||||
sortingByDsf: function(){
|
||||
var inverseAdj = new Map();
|
||||
var keys = this.adj.keys();
|
||||
for(let key of keys) {
|
||||
let blk = this.adj.get(key);
|
||||
if(blk) {
|
||||
for(let v of blk) {
|
||||
if(!inverseAdj.get(v)) {
|
||||
inverseAdj.set(v, [key]);
|
||||
} else {
|
||||
inverseAdj.get(v).push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let inKeys = inverseAdj.keys();
|
||||
let vertexes = new Set([...keys, ...inKeys]);
|
||||
let visited = [];
|
||||
for(let vertex of vertexes) {
|
||||
if(!visited.includes(vertex)) {
|
||||
visited.push(vertex);
|
||||
this.dsf(vertex, inverseAdj, visited);
|
||||
}
|
||||
}
|
||||
},
|
||||
dsf: function(vertex, inverseAdj, visited) {
|
||||
if(!inverseAdj.get(vertex)) {
|
||||
inverseAdj.set(vertex, []);
|
||||
}
|
||||
|
||||
for(let v of inverseAdj.get(vertex)) {
|
||||
if(visited.includes(v)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
visited.push(v);
|
||||
|
||||
this.dsf(v, inverseAdj, visited);
|
||||
}
|
||||
|
||||
console.log("->" + vertex);
|
||||
}
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
var dag = new Graph();
|
||||
dag.addEdge(2, 1);
|
||||
dag.addEdge(3, 2);
|
||||
dag.addEdge(2, 4);
|
||||
dag.addEdge(4, 1);
|
||||
dag.sortingByDsf();
|
||||
|
||||
|
||||
var dag2 = new Graph();
|
||||
dag2.addEdge("main", "parse_options");
|
||||
dag2.addEdge("main", "tail_file");
|
||||
dag2.addEdge("main", "tail_forever");
|
||||
dag2.addEdge("tail_file", "pretty_name");
|
||||
dag2.addEdge("tail_file", "write_header");
|
||||
dag2.addEdge("tail_file", "tail");
|
||||
dag2.addEdge("tail_forever", "recheck");
|
||||
dag2.addEdge("tail_forever", "pretty_name");
|
||||
dag2.addEdge("tail_forever", "write_header");
|
||||
dag2.addEdge("tail_forever", "dump_remainder");
|
||||
dag2.addEdge("tail", "tail_lines");
|
||||
dag2.addEdge("tail", "tail_bytes");
|
||||
dag2.addEdge("tail_lines", "start_lines");
|
||||
dag2.addEdge("tail_lines", "dump_remainder");
|
||||
dag2.addEdge("tail_lines", "file_lines");
|
||||
dag2.addEdge("tail_lines", "pipe_lines");
|
||||
dag2.addEdge("tail_bytes", "xlseek");
|
||||
dag2.addEdge("tail_bytes", "start_bytes");
|
||||
dag2.addEdge("tail_bytes", "dump_remainder");
|
||||
dag2.addEdge("tail_bytes", "pipe_bytes");
|
||||
dag2.addEdge("file_lines", "dump_remainder");
|
||||
dag2.addEdge("recheck", "pretty_name");
|
||||
dag2.sortingByDsf();
|
44
javascript/45_bitmap/bitmap.js
Normal file
44
javascript/45_bitmap/bitmap.js
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
class BitMap {
|
||||
constructor(n) {
|
||||
this.nbits = n;
|
||||
this.blk = new Array(Math.floor(n / 16) + 1);
|
||||
this.blk.fill(0);
|
||||
}
|
||||
|
||||
get(k) {
|
||||
if( k > this.nbits) return false;
|
||||
|
||||
let byteIndex = Math.floor(k / 16);
|
||||
let bitIndex = k % 16;
|
||||
|
||||
return !((this.blk[byteIndex] & (1 << bitIndex)) === 0);
|
||||
}
|
||||
|
||||
set(k) {
|
||||
if( k > this.nbits) return;
|
||||
|
||||
let byteIndex = Math.floor(k / 16);
|
||||
let bitIndex = k % 16;
|
||||
|
||||
this.blk[byteIndex] = this.blk[byteIndex] | (1 << bitIndex);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let aBitMap = new BitMap(20);
|
||||
|
||||
aBitMap.set(1);
|
||||
aBitMap.set(3);
|
||||
aBitMap.set(5);
|
||||
aBitMap.set(7);
|
||||
aBitMap.set(9);
|
||||
aBitMap.set(11);
|
||||
aBitMap.set(13);
|
||||
aBitMap.set(15);
|
||||
aBitMap.set(17);
|
||||
aBitMap.set(19);
|
||||
|
||||
for(let i = 0; i < 21; i++) {
|
||||
console.log(aBitMap.get(i));
|
||||
}
|
@ -52,7 +52,7 @@ class MyArray
|
||||
*/
|
||||
private function checkOutOfRange($index)
|
||||
{
|
||||
if($index > $this->length+1) {
|
||||
if($index >= $this->length) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -68,18 +68,16 @@ class MyArray
|
||||
{
|
||||
$index = intval($index);
|
||||
$value = intval($value);
|
||||
if($index < 0) {
|
||||
if ($index < 0) {
|
||||
return 1;
|
||||
}
|
||||
if($this->checkIfFull()) {
|
||||
|
||||
if ($this->checkIfFull()) {
|
||||
return 2;
|
||||
}
|
||||
if($this->checkOutOfRange($index)) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
for($i=$this->length-1;$i>=$index;$i--) {
|
||||
$this->data[$i+1] = $this->data[$i];
|
||||
for ($i = $this->length - 1; $i >= $index; $i--) {
|
||||
$this->data[$i + 1] = $this->data[$i];
|
||||
}
|
||||
|
||||
$this->data[$index] = $value;
|
||||
@ -96,22 +94,21 @@ class MyArray
|
||||
{
|
||||
$value = 0;
|
||||
$index = intval($index);
|
||||
if($index < 0) {
|
||||
if ($index < 0) {
|
||||
$code = 1;
|
||||
return array($code, $value);
|
||||
return [$code, $value];
|
||||
}
|
||||
if($index != $this->length+1 && $this->checkOutOfRange($index)) {
|
||||
if ($this->checkOutOfRange($index)) {
|
||||
$code = 2;
|
||||
return array($code, $value);
|
||||
return [$code, $value];
|
||||
}
|
||||
|
||||
$value = $this->data[$index];
|
||||
for($i=$index;$i<$this->length-1;$i++) {
|
||||
$this->data[$i] = $this->data[$i+1];
|
||||
for ($i = $index; $i < $this->length - 1; $i++) {
|
||||
$this->data[$i] = $this->data[$i + 1];
|
||||
}
|
||||
|
||||
$this->length--;
|
||||
return array(0, $value);
|
||||
return [0, $value];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,23 +120,23 @@ class MyArray
|
||||
{
|
||||
$value = 0;
|
||||
$index = intval($index);
|
||||
if($index < 0) {
|
||||
if ($index < 0) {
|
||||
$code = 1;
|
||||
return array($code, $value);
|
||||
return [$code, $value];
|
||||
}
|
||||
if($this->checkOutOfRange($index)) {
|
||||
if ($this->checkOutOfRange($index)) {
|
||||
$code = 2;
|
||||
return array($code, $value);
|
||||
return [$code, $value];
|
||||
}
|
||||
return array(0, $this->data[$index]);
|
||||
return [0, $this->data[$index]];
|
||||
}
|
||||
|
||||
public function printData()
|
||||
{
|
||||
$format = "";
|
||||
for($i=0;$i<$this->length;$i++) {
|
||||
$format .= "|".$this->data[$i];
|
||||
for ($i = 0; $i < $this->length; $i++) {
|
||||
$format .= "|" . $this->data[$i];
|
||||
}
|
||||
print($format."\n");
|
||||
print($format . "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ Class SingleLinkedListAlgo
|
||||
++$i;
|
||||
}
|
||||
|
||||
if ($fast == null) {
|
||||
if (null == $fast) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -305,4 +305,4 @@ echo '---------------------- 求链表的中间结点 ----------------------' .
|
||||
$listAlgo->setList($list);
|
||||
$middleNode = $listAlgo->findMiddleNode();
|
||||
var_dump($middleNode->data);
|
||||
echo '-------------------------------------------------------------'. PHP_EOL . PHP_EOL;
|
||||
echo '-------------------------------------------------------------'. PHP_EOL . PHP_EOL;
|
||||
|
@ -13,7 +13,7 @@ function expression($str)
|
||||
$operStack[] = NULL;
|
||||
|
||||
for ($i = 0; $i < count($arr); $i++){
|
||||
if (ord($arr[$i]) >= 48 && ord($arr[$i] <= 57)){
|
||||
if (ord($arr[$i]) >= 48 && ord($arr[$i]) <= 57){
|
||||
array_push($numStack, $arr[$i]);
|
||||
continue;
|
||||
}
|
||||
@ -85,4 +85,4 @@ function compute(&$numStack, &$operStack){
|
||||
}
|
||||
expression('-1+2-(1+2*3)');
|
||||
echo PHP_EOL;
|
||||
eval('echo -1+2-(1+2*3);');
|
||||
eval('echo -1+2-(1+2*3);');
|
||||
|
@ -1,24 +1,67 @@
|
||||
<?php
|
||||
|
||||
function insertSort(&$arr)
|
||||
// 冒泡排序
|
||||
function bubbleSort(&$arr)
|
||||
{
|
||||
$i = 0;
|
||||
$len = count($arr);
|
||||
$length = count($arr);
|
||||
if ($length <= 1) return;
|
||||
|
||||
while($i < $len){
|
||||
$data = $arr[$i+1];
|
||||
for ($j = $i;$j >=0 ;$j-- ){
|
||||
if ($data >= $arr[$j]){
|
||||
array_splice($arr, $i+1, 1);
|
||||
array_splice($arr, ++$j, 0, $data);
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$flag = false;
|
||||
for ($j = 0; $j < $length - $i - 1; $j++) {
|
||||
if ($arr[$i] > $arr[$j + 1]) {
|
||||
$tmp = $arr[$j];
|
||||
$arr[$j] = $arr[$j + 1];
|
||||
$arr[$j + 1] = $tmp;
|
||||
$flag = true;
|
||||
}
|
||||
}
|
||||
if (!$flag) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 插入排序
|
||||
function insertionSort(&$arr)
|
||||
{
|
||||
$n = count($arr);
|
||||
if ($n <= 1) return;
|
||||
|
||||
for ($i = 1; $i < $n; ++$i) {
|
||||
$value = $arr[$i];
|
||||
$j = $i - 1;
|
||||
// 查找插入的位置
|
||||
for (; $j >= 0; --$j) {
|
||||
if ($arr[$j] > $value) {
|
||||
$arr[$j + 1] = $arr[$j]; // 数据移动
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
$arr[$j + 1] = $value; // 插入数据
|
||||
}
|
||||
}
|
||||
|
||||
// 选择排序
|
||||
function selectionSort(&$arr)
|
||||
{
|
||||
$length = count($arr);
|
||||
if ($length <= 1) return;
|
||||
|
||||
for ($i = 0; $i < $length - 1; $i++) {
|
||||
//先假设最小的值的位置
|
||||
$p = $i;
|
||||
for ($j = $i + 1; $j < $length; $j++) {
|
||||
if ($arr[$p] > $arr[$j]) {
|
||||
$p = $j;
|
||||
}
|
||||
}
|
||||
$tmp = $arr[$p];
|
||||
$arr[$p] = $arr[$i];
|
||||
$arr[$i] = $tmp;
|
||||
}
|
||||
}
|
||||
|
||||
$arr = [1,4,6,2,3,5,4];
|
||||
insertSort($arr);
|
||||
var_dump($arr);
|
||||
insertionSort($arr);
|
||||
var_dump($arr);
|
||||
|
@ -1,40 +1,48 @@
|
||||
<?php
|
||||
/*
|
||||
* 归并排序
|
||||
*/
|
||||
|
||||
$arr = [4, 5, 6, 1, 3, 2];
|
||||
$length = count($arr);
|
||||
$arr = [4, 5, 6, 1, 3, 2];
|
||||
$length = count($arr);
|
||||
|
||||
$p = 0;
|
||||
$r = $length - 1;
|
||||
$p = 0;
|
||||
$r = $length - 1;
|
||||
|
||||
$result = $this->mergeSort($arr, $p, $r);
|
||||
$result = mergeSort($arr, $p, $r);
|
||||
|
||||
var_dump($result);
|
||||
var_dump($result);
|
||||
|
||||
|
||||
//递归调用,分解数组
|
||||
function mergeSort(array $arr, $p, $r)
|
||||
{
|
||||
return mergeSortRecursive($arr, $p, $r);
|
||||
}
|
||||
|
||||
// 递归调用函数
|
||||
function mergeSortRecursive(array $arr, $p, $r)
|
||||
{
|
||||
// 递归终止条件
|
||||
if ($p >= $r) {
|
||||
return [$arr[$r]];
|
||||
}
|
||||
|
||||
// 取 p 到 r 之间的中间位置 q
|
||||
$q = (int)(($p + $r) / 2);
|
||||
|
||||
$left = $this->mergeSort($arr, $p, $q);
|
||||
$right = $this->mergeSort($arr, $q + 1, $r);
|
||||
return $this->merge($left, $right);
|
||||
// 分治递归
|
||||
$left = mergeSortRecursive($arr, $p, $q);
|
||||
$right = mergeSortRecursive($arr, $q + 1, $r);
|
||||
return merge($left, $right);
|
||||
}
|
||||
|
||||
//合并
|
||||
// 合并
|
||||
function merge(array $left, array $right)
|
||||
{
|
||||
$tmp = [];
|
||||
|
||||
$i = 0;
|
||||
|
||||
$j = 0;
|
||||
$i = $j = 0;
|
||||
|
||||
$leftLength = count($left);
|
||||
|
||||
$rightLength = count($right);
|
||||
|
||||
do {
|
||||
@ -43,24 +51,23 @@ function merge(array $left, array $right)
|
||||
} else {
|
||||
$tmp[] = $right[$j++];
|
||||
}
|
||||
|
||||
} while ($i < $leftLength && $j < $rightLength);
|
||||
|
||||
|
||||
$start = $i;
|
||||
$end = $leftLength;
|
||||
$copyArr = $left;
|
||||
|
||||
// 判断哪个子数组中有剩余的数据
|
||||
if ($j < $rightLength) {
|
||||
$start = $j;
|
||||
$end = $rightLength;
|
||||
$copyArr = $right;
|
||||
}
|
||||
|
||||
for (; $start < $end; $start++) {
|
||||
$tmp[] = $copyArr[$start];
|
||||
}
|
||||
// 将剩余的数据拷贝到临时数组 tmp
|
||||
do {
|
||||
$tmp[] = $copyArr[$start++];
|
||||
} while ($start < $end);
|
||||
|
||||
return $tmp;
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user