退役太久手生了唉..
目前期望手撕的名单: 1.各种排序(归并/快排/堆排/冒泡选择插入/桶排/基数..) 2.各种数据结构(链表/堆/带旋转的平衡树) 3.杂
主要是C++实现,有空我会接着改为Java(虽然没差
实现方法尽量是人尽皆知的那种
并且实现均会通过OJ测试
1.归并排序
void merge(int *arr, int lo, int mid, int hi) {
int *tmp = (int *)malloc((hi-lo+1)*sizeof(int));
int i = lo, j = mid+1, k = 0;
while(i<=mid && j<=hi) {
if(arr[i] <= arr[j]) tmp[k++] = arr[i++];
else tmp[k++] = arr[j++];
}
while(i <= mid) tmp[k++] = arr[i++];
while(j <= hi) tmp[k++] = arr[j++];
memcpy(arr+lo, tmp, k*sizeof(int));
free(tmp);
}
void mergeSort(int *arr, int lo, int hi) {
if(lo == hi) return;
int mid = lo+hi >> 1;
mergeSort(arr, lo, mid);
mergeSort(arr, mid+1, hi);
merge(arr, lo, mid, hi);
}
Java version
package com.caturra.sorting;
import java.util.*;
/**
* 归并排序,个人习惯使用全闭区间,[lo,hi]
* @author Caturra
*
*/
public class MergeSort {
public static void sort(Comparable[] comps,int lo,int hi) {
if(lo >= hi) return;
int mid = lo+hi >> 1;
sort(comps,lo,mid);
sort(comps,mid+1,hi);
merge(comps,lo,mid,hi);
}
private static void merge(Comparable[] comps,int lo,int mid,int hi) {
Comparable[] temp = new Comparable[hi-lo+1];
int i = lo, j = mid+1, k = 0;
while(i <= mid && j <= hi) {
int cmp = comps[i].compareTo(comps[j]);
if(cmp < 0) {
temp[k++] = comps[i++];
} else {
temp[k++] = comps[j++];
}
}
while(i <= mid) temp[k++] = comps[i++];
while(j <= hi) temp[k++] = comps[j++];
for(k = lo; k <= hi; k++) comps[k] = temp[k-lo];
}
/**
* 测试样例,HDU1425
* @param args
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
int n = sc.nextInt();
int m = sc.nextInt();
Integer[] arr = new Integer[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
sort(arr, 0, n-1);
for(int i = 0; i < n/2; i++) {
arr[i] ^= arr[n-i-1];
arr[n-i-1] ^= arr[i];
arr[i] ^= arr[n-i-1];
}
for(int i = 0; i < m-1; i++) System.out.print(arr[i]+" ");
System.out.println(arr[m-1]);
}
}
}
2.快排
快排几乎没敲过,过去太依赖sort了..
需要注意的点:
1.找轴点时i经过的地方必然保证小于未来的基准点,j同理必然大于未来的基准点,因此交错时则停止扫描
\(comps[1...i-1] \lt p\) 交错后\(j=i-1\),存在\(comps[0]>comps[j]\)的可能,因此还需要进一步交换满足轴点的定义
既交错后\(comps[j] \geq comps[0...j-1]\)是最后一步保证的,\(comps[j] \lt comps[j+1...hi]\)是先前的双指针交换保证的
2.j>=0是恒成立的,最后可能停留在0
3.有序表现很惨
Cpp实现参考自邓俊辉老师的写法,相当简洁
// trick:找轴点前先rand一下才能保证复杂度
int partition(int *arr, int lo,int hi) {
swap(arr[lo], arr[lo+rand()%(hi-lo+1)]);
int val = arr[lo], pivot = lo;
for(int i = lo+1; i <= hi; i++) {
if(arr[i] < val) swap(arr[++pivot], arr[i]);
}
swap(arr[lo], arr[pivot]);
return pivot;
}
void quickSort(int *arr, int lo,int hi) {
if(lo >= hi) return;
int pivot = partition(arr, lo, hi);
quickSort(arr, lo, pivot-1);
quickSort(arr, pivot+1, hi);
}
Java version
package com.caturra.sorting;
import java.util.Scanner;
public class QuickSort {
public static void sort(Comparable[] comps,int lo,int hi) {
if(lo >= hi) return;
int j = partition(comps,lo,hi);
sort(comps,lo,j-1);
sort(comps,j+1,hi);
}
private static int partition(Comparable[] comps,int lo,int hi) {
exch(comps,lo,(int)(lo+Math.random()*(hi-lo))); //通常需要随机化
Comparable val = comps[lo];
int i = lo, j = hi+1;
while(true) {
while(i < hi && comps[++i].compareTo(val) < 0);
while(j > lo && comps[--j].compareTo(val) > 0);
if(i >= j) break;
exch(comps,i,j);
}
exch(comps,lo,j);
return j;
}
private static void exch(Object[] comps,int i,int j) {
Object t = comps[i];
comps[i] = comps[j];
comps[j] = t;
}
public static void main(String[] args) {
// 测试同上
}
}
为了处理重复数过多带来的劣化而引入三向切分的方法
public static void sort(Comparable[] comps,int lo,int hi) {
if(lo >= hi) return;
int lt = lo, gt = hi, i = lo+1;
Comparable val = comps[lo];
while(i <= gt) {
int cmp = comps[i].compareTo(val);
if(cmp < 0) exch(comps,lt++,i++); //comps[i]太小,放入已经排好序的[0,lo)当中,此时和lt连续接壤
else if(cmp > 0) exch(comps,i,gt--); //放入大于val的一边,引入的[gt]接着比较
else i++;
}
sort(comps,lo,lt-1);
sort(comps,gt+1,hi); //此时[lt,gt]都是重复存在的数
}
3.\(O(n^2)\)排序俱乐部
// 相当直观的写法,有一种高逼格写法学不来(
void bubbleSort(int *arr, int lo, int hi) {
bool isSorted = false;
while(!isSorted) {
isSorted = true;
for(int i = lo; i < hi; i++) {
if(arr[i] > arr[i+1]) {
swap(arr[i], arr[i+1]);
isSorted = false;
}
}
}
}
/***************************************************/
//trick:倒过来交换是不断挑选最优插入点的过程
void insertSort(int *arr, int lo, int hi) {
for(int i = lo+1; i <= hi; i++) {
int j = i;
while(j>lo && arr[j]<arr[j-1]) {
swap(arr[j], arr[j-1]);
--j;
}
}
}
/***************************************************/
// 毫无实现难度
void selectSort(int *arr, int lo, int hi) {
for(int i = lo; i <= hi; i++) {
int minIdx = i;
for(int j = i; j <= hi; j++) {
if(arr[j] < arr[minIdx]) {
minIdx = j;
}
}
swap(arr[i], arr[minIdx]);
}
}
4.heap简略版 / 没有封装堆排 / 没有O(n)构造
struct Heap {
int heap[MAXN],tot;
void init(){
tot=0;
}
void insert(int val) {
heap[++tot]=val;
int now = tot;
while(heap[now] < heap[now>>1]) {
swap(heap[now],heap[now>>1]);
now >>= 1;
}
}
int pop() {
int res = heap[1];
heap[1] = heap[tot--];
int now = 1;
while(now*2 <= tot) {
int nxt = now<<1;
if(nxt+1<=tot && heap[nxt+1] < heap[nxt]) nxt++; // find min
if(heap[now] < heap[nxt]) return res;
swap(heap[now], heap[nxt]);
now = nxt;
}
return res;
}
}h;
5.KMP
char text[MAXN], pattern[MAXN];
int f[MAXN], nxt[MAXN];
void init() {
int len = strlen(pattern+1);
int j = 0;
nxt[1] = 0;
for(int i = 2; i <= len; i++) {
while(j>0 && pattern[i]!=pattern[j+1]) j = nxt[j];
if(pattern[i] == pattern[j+1]) j++;
nxt[i] = j;
}
}
int match() {
int n = strlen(text+1), m = strlen(pattern+1);
int j = 0, ans = 0;
for(int i = 1; i <= n; i++) {
while(j>0 && (j==m || text[i]!=pattern[j+1])) j = nxt[j];
if(text[i] == pattern[j+1]) j++;
f[i] = j;
if(f[i] == m) ans++;
}
return ans;
}
6.Huffman编码(丑
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+11;
struct Node {
int lc, rc;
int weight;
char val;
int id;
Node() {}
Node(int _id,int _weight,char _val) {
id = _id, weight = _weight, val = _val,
lc = rc = 0;
}
bool operator < (const Node &rhs) const {
return weight > rhs.weight;
}
}huffman[MAXN]; int tot;
priority_queue<Node> pq;
string ans[128];
string tmpBit;
void dfs(int now) {
if(huffman[now].val) {
ans[huffman[now].val] = tmpBit;
}
tmpBit.push_back('0');
if(huffman[now].lc) dfs(huffman[now].lc);
tmpBit.pop_back();
tmpBit.push_back('1');
if(huffman[now].rc) dfs(huffman[now].rc);
tmpBit.pop_back();
}
int num[128];
string str;
int main() {
while(cin >> str) {
memset(num,0,sizeof num);
tot = 0;
while(!pq.empty()) pq.pop();
int all = 0, allId = 0;
for(int i = 0; i < str.length(); i++) {
if(num[str[i]] == 0) all++, allId = str[i];
num[str[i]]++;
}
if(all == 1) {
cout << (char)allId <<":: " << 0 << endl;
cout << "totLength: " << str.length() << endl;
cout << "rate: " << str.length() << endl;
continue;
}
for(int i = 1; i < 128; i++) {
if(!num[i]) continue;
huffman[++tot] = Node(tot,num[i],i);
pq.push(huffman[tot]);
}
while(pq.size() > 1) {
Node tmp1 = pq.top(); pq.pop();
Node tmp2 = pq.top(); pq.pop();
huffman[++tot] = Node(tot,tmp1.weight+tmp2.weight,0);
huffman[tot].lc = tmp1.id;
huffman[tot].rc = tmp2.id;
pq.push(huffman[tot]);
}
for(int i = 0; i < 128; i++) ans[i].clear();
tmpBit.clear();
dfs(tot);
long long totLen = 0;
vector<char> characters;
int uniqueLength = 0;
for(int i = 0; i < 128; i++) {
if(num[i]) {
cout<<(char)i<<":: "<<ans[i]<<endl;
characters.push_back(i);
uniqueLength += ans[i].length();
}
totLen += num[i] * ans[i].length();
}
cout << "totLength: " << totLen << endl;
cout << "rate: " << 8.0*str.length() / totLen << endl;
int *encoded = (int *) malloc(((uniqueLength+31)/32)*sizeof(int));
memset(encoded,0,sizeof encoded);
int nowLength = 0;
for(int i = 0; i < characters.size(); i++) {
for(int j = 0; j < ans[characters[i]].size(); j++) {
int x = nowLength / 32;
int y = nowLength % 32;
int z = 0;
if(ans[characters[i]][j] == '1') {
z = 1;
}
encoded[x] |= (z<<y);
nowLength++;
}
}
cout<<"ordered table: ";
for(int i = 0; i < characters.size(); i++) {
cout<<(char)characters[i]<<" ";
}
cout<<endl;
nowLength = 0;
for(int i = 0; i < characters.size(); i++) {
for(int j = 0; j < ans[characters[i]].size(); j++) {
int x = nowLength / 32;
int y = nowLength % 32;
cout<<(encoded[x]>>y&1);
nowLength++;
}
cout<<"|";
}
cout<<endl;
}
return 0;
}
堆(new version)
这次的堆实现是按照算法导论的思路写的
import java.util.Arrays;
import java.util.Scanner;
// 默认大根堆
public class MyHeap {
public int[] heap;
public int size;
public boolean heapStatus;
public MyHeap(int capacity) {
heap = new int[capacity];
size = 0;
}
public int down(int size,int idx) {
int mx = 0;
int res = heap[idx];
while(mx != idx) {
mx = idx;
int lc = idx << 1;
int rc = idx << 1 |1;
if(lc <= size && heap[lc] > heap[idx]) {
mx = lc;
}
if(rc <= size && heap[rc] > heap[mx]) {
mx = rc;
}
if(mx != idx) {
res = Math.max(res,heap[mx]);
swap(heap,mx,idx);
idx = mx; // idx换成了mx 但val还是原来下沉的那个
mx = 0;
}
}
return res;
}
public void build(int[] arr) {
for(int i = 1; i <= arr.length; i++) {
heap[i] = arr[i-1];
}
size = arr.length;
for(int i = size>>1; i >= 1; --i) {
down(size,i);
}
heapStatus = true;
}
public void swap(int[] arr,int i,int j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
public void heapSort(int[] arr) {
build(arr);
for(int i = size; i >= 2; --i) {
swap(heap,1,i);
down(i-1,1);
}
}
public void up(int i) {
while(i > 1 && heap[i] > heap[i>>1]) {
swap(heap,i,i>>1);
i >>= 1;
}
}
public void insert(int val) {
heap[++size] = val;
up(size);
}
public int remove() {
int res = down(size,1);
swap(heap,1,size--);
down(size,1);
return res;
}
public static void main(String[ ] args) {
MyHeap heap = new MyHeap(222);
int[] arr = new int[] {0,5,2,67,4,1,6,9,3,2,11,7,0};
heap.build(arr);
System.out.println(Arrays.toString(heap.heap));
System.out.println("built");
heap.insert(5);
heap.insert(666);
heap.insert(-1);
heap.remove();
System.out.println("rm:"+heap.remove());
// System.out.println("rm:"+heap.remove());
// heap.heapSort(arr);
System.out.println(Arrays.toString(heap.heap));
}
}
LCA-RMQ实现
import java.util.HashMap;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
class Solution {
public HashMap<TreeNode,Integer> dep = new HashMap<>();
public HashMap<TreeNode,TreeNode>[] p = new HashMap[20];
public void dfs(TreeNode rt,TreeNode fa) {
if(fa == null) {
dep.put(rt,0);
p[0].put(rt,rt);
}
else {
dep.put(rt,dep.get(fa)+1);
p[0].put(rt,fa);
}
for(int i = 1; i < 20; i++) {
p[i].put(rt,p[i-1].get(p[i-1].get(rt)));
}
if(rt.left != null) dfs(rt.left,rt);
if(rt.right != null) dfs(rt.right,rt);
}
TreeNode lca(TreeNode u,TreeNode v) {
if(dep.get(u) < dep.get(v)) {
TreeNode t = u;
u = v;
v = t;
}
for(int i = 0; i < 20; i++) {
if((dep.get(u)-dep.get(v) >>i&1) == 1) {
u = p[i].get(u);
}
}
if(u == v) return u;
for(int i = 19; i >= 0; --i) {
if(p[i].get(u) != p[i].get(v)) {
u = p[i].get(u);
v = p[i].get(v);
}
}
return p[0].get(u);
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || p == null || q == null) return null;
for(int i = 0; i < 20; i++) this.p[i] = new HashMap<>();
dfs(root,null);
return lca(p,q);
}
}