Acmer must be able to tear the code

When it is required not to bring the board and use STL, the code can only be torn by hand.

Moreover, the hand-written words indicate a deeper understanding of the knowledge points and a faster speed during the game. (Although I retired)

However, it is likely that you will not be able to use STL during the written interview. This time will test your understanding of the basic algorithm (memory)

Generally speaking, the code that appears in the advanced guide of the algorithm competition must be tearable

Basic algorithm

Dichotomy

  • Find the smallest of $ \ geq x $ in monotonically increasing sequence \ (a \)
  while(l<r){
      int mid = (l+r)>>1;/*右移运算 相当于除2并且向下取整*/
      if(a[mid]>=x) r=mid;
      else l=mid+1;
  }
  return a[l];
  • Find the largest of the numbers in \ (\ leq x \) in the monotonically increasing sequence \ (a \)
  while(l<r){
      int mid = (l+r+1)>>1;
      if(a[mid]<=x) l=mid;
      else r=mid-1;
  }
  return a[l];

If the answer with the smallest answer is selected, initialize \ (l = L, r = R + 1 \) , if the answer is \ (R + 1 \) then it is not found

If you choose the one that satisfies the largest answer, initialize \ (l = L-1, r = R \) , if the answer is \ (L-1 \) then it is not found

Like in upper_bound()and lower_bound(), if it does not exist, it does return the last subscript +1, vector returnsend()

Sort

Bubble Sort

Adjacent comparison, large right shift

void bubble_sort() {
	for (int i = n - 1; i > 0; --i) {
		bool flag = false;
		for (int j = 0; j + 1 <= i; ++j) 
			if (a[j] > a[j + 1]) { 
				std::swap(a[j], a[j + 1]);
				flag = true;
			}
		if (!flag) return ; 
	}
	return ;
}

Select sort

Select a key, the largest right shift

void selection_sort() {
	for (int i = 0; i < n; ++i) {
		for (int j = i + 1; j < n; ++j) {
			if(a[i] > a[j]) 
				std::swap(a[i], a[j]);
		}
	}
}

Insert sort

In the case of order in the front, select the key to insert in the position where it should be

int i,j,key;
for(i = 2;i <= n;++i){
    key = a[i];
    j = i - 1;
    while(j > 0 && a[j] > key){
        a[j+1] = a[j];
        j--;
    }
    a[j] = key;
}

Quick sort

The number between the selected, the left must be smaller than it, the right must be larger than it, and then recursive divide and conquer

void quick_sort(int l, int r) {
	if (l >=r ) return ;
	int i = l - 1, j = r + 1, x = a[(l + r) >> 1];
	while (i < j) {
		do j--; while (a[j] > x);
		do i++; while (a[i] < x);
		if (i < j) std::swap(a[i], a[j]);
		else quick_sort(l, j), quick_sort(j + 1, r);
	}
}

Merge sort

int merge_sort(int l, int r) {
	if (l >= r) return 0;
	int mid = (l + r) >> 1, res = 0;
 
	res += merge_sort(l, mid);
	res += merge_sort(mid + 1, r);
 
	int i = l, j = mid + 1, cnt = 0;
	while (i <= mid && j <= r) 
		if (a[i] <= a[j]) 
			b[cnt++] = a[i++];
		else {
			res += mid - i + 1;
			b[cnt++] = a[j++];
		}
 
	while (i <= mid) b[cnt++] = a[i++];
	while (j <= r) b[cnt++] = a[j++];
 
	for (int i = l, j = 0; j < cnt; ++i, ++j) a[i] = b[j];
	return res;
}

Heap sort

Implementation of large root heap: x node must be greater than the child node

struct heap{
    int *A;
    int length;
    heap(int n){
        length = n;
        A = new int[n+5];
        for(int i=1;i<=n;++i){
            cin>>A[i];
        }
    }
    void Max_Heapify(int pos){
        int l = pos*2;
        int r = pos*2+1;
        int largest;
        if(l <= length && A[l] > A[pos]){
            largest = l;
        }else{
            largest = pos;
        }
        if(r <= length && A[r] > A[largest]){
            largest = r;
        }
        if(largest != pos){
            swap(A[pos],A[largest]);
            Max_Heapify(largest);
        }
    }
    void build_max_heap(){
        for(int i=length/2;i>=1;--i){
            Max_Heapify(i);
        }
    }
    void heapSort(){
        build_max_heap();
        int n = length;
        for(int i=length;i>=2;--i){
            swap(A[1],A[i]);
            length--;
            Max_Heapify(1);
        }
        for(int i=1;i<=n;++i){
            cout<<A[i]<<" ";
        }
    }
};

Hash

Just remember a formula:

\[H(T) = H(S+T)-H(S)*p^{Length(T)} \]

\ (H (x) \) : the hash value of the string \ (x \)

\ (p \) : hexadecimal number

\ (p ^ x \) means the value shifted to the left by \ (x \) bits under \ (p \) base

As long as the code is pre-processed \ (f (x) \) : prefix hash value \ (p (x) \) : \ (p ^ x \)

Large numbers

Most interviewers said they want to be object-oriented? Is it readable?

Use three stacks to maintain the addition of large numbers (the interviewer said the readable method)

#include<bits/stdc++.h>
using namespace std;
class bigNum{
private:
    stack<int>num1,num2,sum;
public:
    char *Num;
    bigNum(char *s){
        Num = s;
    }
    bigNum* add(bigNum* &right){
        for(int i=0;Num[i];++i){
            num1.push(Num[i] - '0');
        }
        for(int i=0;right->Num[i];++i){
            num2.push(right->Num[i] - '0');
        }
        int flag = 0,tmp,x,y;
        while(!num1.empty() || !num2.empty()){
            x = num1.empty() == 1 ? 0:num1.top();
            y = num2.empty() == 1 ? 0:num2.top();
            tmp = x + y + flag;
            flag = tmp/10;
            sum.push(tmp%10);
            if(!num1.empty()) num1.pop();
            if(!num2.empty()) num2.pop();
        }
        if(flag){
            sum.push(flag);
        }
        char *ans = new char[sum.size()+1];
        int pos = 0;
        while(!sum.empty()){
            ans[pos++] = sum.top() + '0';
            sum.pop();
        }
        return new bigNum(ans);
    }
    void printNum(){
        cout<<Num<<endl;
    }
};
char a[150],b[150];
int main(){
    cin>>a;
    cin>>b;
    bigNum *left = new bigNum(a);
    bigNum *right = new bigNum(b);
    bigNum *sum = left ->add(right);
    sum ->printNum();
    return 0;
}

String

Dictionary tree

void ins(char *str){
    int len=strlen(str);
    int p=0;
    for(int i=0; i<len; i++){
        int ch=str[i]-'a';
        if(!tire[p][ch])
            tire[p][ch]=++ant;
        p=tire[p][ch];
    }
    cnt[p]++;
}
int srh(char *str){
    int ans=0;
    int len=strlen(str);
    int p=0;
    for(int i=0; i<len; i++){
        int ch=str[i]-'a';
        p=tire[p][ch];
        if(!p) return ans;
        ans+=cnt[p];
    }
    return ans;
}

In fact, there are pointer writing methods, maybe the interviewer can only understand the pointer

const int maxn = 26;
struct tireNode{
    tireNode* next[maxn];
    bool endpos;
    tire(){
        endpos = 0;
    }
};
struct tire{
    tireNode *root;
    tire(){
        root = new tireNode();
    }
    void Insert(char *str){
        tireNode *now = root;
        while(*str != '\0'){
            int pos = *str - 'a';
            if(now->next[pos] == nullptr){
                now -> next[pos] = new tireNode();
            }
            now = now -> next[pos];
            str++;
        }
        now -> endpos = 1;
    }
    bool Find(char *str){
        tireNode *now = root;
        while(*str != '\0'){
            int pos = *str - 'a';
            if(now -> next[pos] == nullptr){
                return 0;
            }
            now = now -> next[pos];
            str++;
        }
        return now -> endpos;
    }
};

KMP

\ (Next [i] \) : indicates the maximum matching position of the prefix and suffix of the string \ ([0 ... i] \) , neither the suffix nor the suffix can include itself

So \ (Next [0] =-1 \) , because the first character must not have this maximum matching position

So \ (i \) starts from 1, \ (j \) starts from -1

According to the loop invariant, maintained in the course of the loop, $ Next [i] \ (finally must be equal to \) j \ (, ie \) [0 ... j] \ (must be the longest with \) i $ Is the string whose ending suffix matches the pattern string prefix.

void get_Next(char *p){
    Next[0] = -1;
    int i = 1,j = -1;
    while(p[i] != '\0'){
        while(j != -1 && p[i] != p[j+1]) j = Next[j];
        if(p[i] == p[j+1])++j;
        Next[i++] = j;
    }
}
int kmp(char *s,char *p){
    int i = 0,j = -1;
    int ans = 0;
    while(s[i] != '\0'){
        while(j != -1 && ( p[j+1] == '\0' || s[i] != p[j+1]))j = Next[j];
        if(s[i] == p[j+1])++j;
        f[i++] = j;
        if(p[j+1] == '\0'){
           //视情况
        }
    }
    return ans;
}

AC automaton

The key point is to find the first \ (tr [u] [i] \) that is not empty from the fafail sequence. In order to save time, path compression is used.

namespace AC {
    int tr[N][26], tot;
    int e[N], fail[N];

    void insert(char *s) {
        int u = 0;
        for (int i = 1; s[i]; ++i) {
            if (!tr[u][s[i] - 'a']) tr[u][s[i] - 'a'] = ++tot;
            u = tr[u][s[i] - 'a'];
        }
        e[u]++;
    }

    queue<int> q;

    void build() {
        for (int i = 0; i < 26; ++i) {
            if (tr[0][i]) {
                q.push(tr[0][i]);
            }
        }
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = 0; i < 26; ++i) {
                if (tr[u][i]) {
                    fail[tr[u][i]] = tr[fail[u]][i];
                    q.push(tr[u][i]);
                } else {
                    tr[u][i] = tr[fail[u]][i];
                }
            }
        }
    }

    int query(char *t) {
        int u = 0, res = 0;
        for (int i = 1; t[i]; i++) {
            u = tr[u][t[i] - 'a'];  
            for (int j = u; j && e[j] != -1; j = fail[j]) {
                res += e[j], e[j] = -1;
            }
        }
        return res;
    }
}

mathematics

Linear sieve

Adoption properties: every non-prime number has a smallest prime factor

void get_prime(){
    int pos = 0;
    for(int i=2;i<N;++i){
        if(!check[i]) {
            Prime[pos++]=i;
        }
        for(j=0;j < pos && i*Prime[j] < N;++j){
            check[i * Prime[j]] = true;
            if(i % Prime[j] == 0) {
                break;
            }
        }
    }
}

Approximate number

Multiple method to get positive divisor set

for(int i = 1;i <= n;++i){
    for(int j = 1;j <= n/i;++j){
        factor[i*j].push_back(i);
    }
}

Divisor of a single number: try division

for(int i = 1;i * i <= n;++i){
    if(n % i == 0){
        factor[++m] = i;
        if(i != n/i) factor[++m] = n/i;
    }
}

data structure

Balance tree

At least it will be flipped, if not the root node, you canRotate

	inline void Rotate(int x) {
        int y = s[x].fa, z = s[y].fa, chk = get(x);

        //y与x的子节点相连
        s[y].ch[chk] = s[x].ch[chk ^ 1];
        s[s[x].ch[chk ^ 1]].fa = y;

        //x与y父子相连
        s[x].ch[chk ^ 1] = y;
        s[y].fa = x;

        // x与y的原来的父亲z相连
        s[x].fa = z;
        if(z) s[z].ch[y == s[z].ch[1]] = x;

        //只有x和y的sz变化了
        maintain(y);
        maintain(x);
    }

Tree array

int ask(int x){
    int ans = 0;
    for(;x;x -= x & -x) ans += c[x];
    return ans;
}
void add(int x,int y){
    for(;x <= N;x += x & -x) c[x] += y;
}

Line tree

struct node{
	int l,r;
	int sum,add;//和,延迟标记
}t[maxn << 2];
void build(int p,int l,int r){//后序遍历
	t[p].l = l,t[p].r;
	if(l == r) {t[p].sum = s[l];return;}
	int mid = (l+r) >> 1;
	build(p << 1,l,mid);
	build(p << 1 |1,mid + 1,r);
	t[p].sum = t[p << 1].sum + t[p << 1 | 1].sum;//更新来自子结点的答案
}
void spread(int p){
	if(add(p)){//如果有标记
		t[p << 1].sum = t[p].add * (t[p << 1].r - t[p << 1].l + 1);
		t[p << 1 | 1].sum = t[p].add * (t[p << 1 | 1].r - t[p << 1 | 1].l + 1);
		t[p << 1].add += t[p].add;
        t[p << 1 | 1].add += t[p].add;
        t[p].add;
	}
}
void change(int p,int l,int r,int d){
    /*if(t[p].l == t[p].r){
    	t[p].sum += d;
    }如果不用延迟标记
    */
	if(l <= t[p].l && r >= t[p].r){
		t[p].sum += d * (t[p].r - t[p].l + 1);
        t[p].add += d;
        return;
	}
	spread(p);
	int mid = t[p].l + t[p].r >> 1;
	if(l <= mid) change(p << 1,l,r,d);
	if(r > mid) change(p << 1 | 1,l,r,d);
    t[p].sum = t[p << 1].sum + t[p << 1 | 1].sum;//更新来自子结点的答案
}
long long ask(int p,int l,int r){
    if(l <= t[p].l && r >= t[p].r){
        return t[p].sum;
    }
    long long ans = 0;
    int mid = (t[p].l + t[p].r) >> 1;
    if(l <= mid) ans += ask(p << 1,l,r);
   	if(r > mid) ans += ask(p << 1|1,l,r);
    return ans;
}

Graph Theory

Shortest dij

  1. Initialize d [1] = 0, the remaining nodes are positive infinity
  2. Find an unmarked node with the smallest \ (d [x] \) \ (x \) and marked node \ (x \)
  3. Scan all the outgoing edges of the node \ (x \) \ ((x, y, z) \) , if \ (d [y]> d [x] + z \) , use \ (d [x] + z \) Update \ (y \)
memset(d,inf,sizeof(d));
d[1] = 0;
q.push(make_pair(0,1));
while(!q.empty()){
 	int x = q.top().second;
    q.pop();
    if(v[x]) continue;
    v[x] = 1;
    for(int i=head[x];i;i=e[i].next){
        int y = e[i].to;
        int z = e[i].val;
        if(d[y] > d[x] + z){
            d[y] = d[x] + z;
            q.push(make_pair(-d[y],y));
        }
    }
}

Minimum spanning tree

  1. Establish and check sets, each point constitutes a set
  2. Sort all the edges by weight from small to large, and scan each edge in turn \ ((x, y, z) \)
  3. If \ (x, y \) belongs to the same set (connected), then ignore this edge
  4. Otherwise, merge the set where \ (x, y \) is located and accumulate \ (z \) into the answer
int get(int x){
    if (x == fa[x]) return x;
    return fa[x] = get(fa[x]);
}
void solve(){
    for(int i=1;i<=n;++i) fa[i] = i;//1
    sort(e + 1,e + 1 + m,cmp);//2
    int ans = 0;
    for(int i = 1;i <= m;++i){
    	int x = get(e[i].x);
        int y = get(e[i].y);
        if(x != y){
            fa[x] = y;
            ans += e[i].z;
        }
    }
}

Hungarian algorithm

bool dfs(int x){
    for(int i=head[x];i;i=e[i].next) {
        if(!vis[y = e[i].to]){
            vis[y] = 1;
            if(!match[y] || dfs(match[y])) {
                match[y] = x;
                return true;
            }
        }
    }
}
for(int i = 1;i <= n; ++i){
    memset(vis,0,sizeof(vis));
    if (dfs(i)) {ans++;}
}

Guess you like

Origin www.cnblogs.com/smallocean/p/12681559.html