Random

keaucucal

NAME  | keaucucal
BIRTH | 2008
FROM  | Taoyuan
CLASS | 106
HATE  | IanWen
PHOTO | Not Availible

NOTE: Hello World!

WHOAMI

Random

keaucucal

WHOAMI

NAME  | keaucucal
BIRTH | 2008
FROM  | Taoyuan
CLASS | 106
HATE  | IanWen
PHOTO | Not Availible

NOTE: Hello World!

INDEX

introduction

k-th smallest

hash

1.QuickSort

2.What is random

3.How to random

4.Classification

1.QuickSort

2.QuickSelect

1.Hashing

2.Collision

3.Polynomial

4.Problems

WHOAMI

NAME  | keaucucal
BIRTH | 2008
FROM  | Taoyuan
CLASS | 106
HATE  | IanWen
PHOTO | Not Availible

NOTE: Hello World!

Introduction

QuickSort

void quickSort(int l, int r) {
	int pivot = arr[r];
    
    ... // 把小於 pivot 的放左邊,大於的放右邊
    
    quickSort(l, pivotIndex - 1);
    quickSort(pivotIndex + 1, r);
}

QuickSort

void quickSort(int l, int r) {
	int pivot = arr[r];
    
    ... // 把小於 pivot 的放左邊,大於的放右邊
    
    quickSort(l, pivotIndex - 1);
    quickSort(pivotIndex + 1, r);
}

期望

最壞

(r - l) / 2

(r - l) / 2

1

(r - l) - 1

O(N^2)
O(N log N)

如何防止惡意測資?

void quickSort(int l, int r) {
	int pivotIndex = l + rand() % (r - l + 1);
    
    ... // 把小於 pivot 的放左邊,大於的放右邊
    
    quickSort(l, pivotIndex - 1);
    quickSort(pivotIndex + 1, r);
}

{1, 2, 3, 4, 5, 6}

Random

What is        ? ? ?

Random

A algorithm that use

function.

How to Random?

#include <iostream>
using namespace std;

int main() {
	srand(time(NULL)); // 設定亂數種子等於當前時間
    
    int x = rand(); // 0 ~ RAND_MAX
    cout << x;
}

Rand()

#include <iostream>
#include <random>
using namespace std;

int main() {
    // 使用種子初始化 mt19937
    mt19937 gen(807); 
    
    // 定義範圍在 1 到 100 之間的均勻分佈
    uniform_int_distribution<> dis(1, 100); 

    cout << dis(gen);
}

mt19937

- 高度的隨機性

- 高效率

- 高均勻分布

How to Random?

Las Vegas

Monte Carlo

- 簡單

優點?

缺點?

- 隨機性差(容易重複)

- 生成範圍限制

- 不同電腦結果不固定

就算種子固定

Rand()

mt19937

Las Vegas

Monte Carlo

有可能給出錯誤答案

一定給出正確答案

但運行速度隨機

隨機的分類

Las Vegas

Monte Carlo

有可能給出錯誤答案

一定給出正確答案

但運行速度隨機

讓錯誤機率變小

別出現Worst Case

隨機的分類

Las Vegas

Monte Carlo

有可能給出錯誤答案

一定給出正確答案

但運行速度隨機

讓錯誤機率變小

別出現Worst Case

隨機的分類

k-th Smallest

int main() {
	sort(arr.begin(), arr.end());
    cout << arr[k]; // 1-based
}
O(n \log n)
void quickSort(int l, int r) {
	int pivotIndex = l + rand() % (r - l + 1);
    
    ... // 把小於 pivot 的放左邊,大於的放右邊
    
    quickSort(l, pivotIndex - 1);
    quickSort(pivotIndex + 1, r);
}

Smaller

Pivot

Bigger

QuickSort

QuickSort

void quickSort(int l, int r) {
	int pivotIndex = l + rand() % (r - l + 1);
    
    ... // 把小於 pivot 的放左邊,大於的放右邊
    
    quickSort(l, pivotIndex - 1);
    quickSort(pivotIndex + 1, r);
}

Smaller

Pivot

Bigger

如果 k 在這?

QuickSort

void quickSort(int l, int r) {
	int pivotIndex = l + rand() % (r - l + 1);
    
    ... // 把小於 pivot 的放左邊,大於的放右邊
    
    quickSort(l, pivotIndex - 1);
    quickSort(pivotIndex + 1, r);
}

Smaller

Pivot

Bigger

如果 k 在這?

void quickSort(int l, int r) {
	int pivotIndex = l + rand() % (r - l + 1);
    
    ... // 把小於 pivot 的放左邊,大於的放右邊
    
    if (k == pivotIndex) {
    	cout << k;
    } else if (k < pivotIndex) {
    	quickSort(l, pivotIndex - 1); // 只排左邊
    } else {
    	quickSort(pivotIndex + 1, r); // 只排右邊
    }
}

Smaller

Pivot

Bigger

QuickSort

QuickSelect

其實這叫做

QuickSelect

其實這叫做

void quickSort(int l, int r) {
	int pivotIndex = l + rand() % (r - l + 1);
    
    ... // 把小於 pivot 的放左邊,大於的放右邊
    
    if (k == pivotIndex) {
    	cout << k;
    } else if (k < pivotIndex) {
    	quickSort(l, pivotIndex - 1); // 只排左邊
    } else {
    	quickSort(pivotIndex + 1, r); // 只排右邊
    }
}

其實這叫做

#include <bits/stdc++.h>
using namespace std;

vector<int> arr = {10, 4, 5, 8, 6, 11, 26};
int k = 3; // 0-based -> 4th smallest

int quickSelect(int l, int r) {
    if (l == r) {
        return arr[l];
    }

    int pivotIndex = l + rand() % (r - l + 1);
	swap(arr[pivotIndex], arr[r]); // 換到最後
	int pivot = arr[r];
	pivotIndex = l;

	for (int j = l; j < r; j++) {
		if (arr[j] <= pivot) {
			swap(arr[pivotIndex], arr[j]);
			pivotIndex++;
		}
	}

	swap(arr[pivotIndex], arr[r]);

	// 判斷往哪邊搜
    if (k == pivotIndex) {
        return arr[k];
    } else if (k < pivotIndex) {
        return quickSelect(l, pivotIndex - 1);
    } else {
        return quickSelect(pivotIndex + 1, r);
    }
}

int main() {
    srand(time(NULL));
	
    cout << "The " << k + 1 << "rd smallest element is: "
              << quickSelect(0, arr.size() - 1) << endl;
}

Hash

另外一個Random運用

將輸入轉換成固定格式輸出的過程。

For Example:

讀入一個數字,返回他除以某個數的餘數

- 25 % 10 = 5

- 37 % 10 = 7

- 100 % 10 = 0

807 % 10 = ?

碰撞啦

Hashing

有無限種輸入,但有限種輸出,當輸入不一樣但輸出一樣時,稱為碰撞

假設最後會 % B

場景1:兩個數字比對

場景2:一個數字跟n個數字比對

場景3:n個數字互相比對

1 / B
1 - \left(1 - \frac{1}{B}\right)^n
1 - \frac{B \cdot (B-1) \cdot (B-2) \cdots (B-n+1)}{B^n}
B 場景1 場景2 場景3
1e3 0.001000 1.000000 1.000000
1e6 0.000001 0.632121 1.000000
1e9 0.000000 0.001000 1.000000
1e12 0.000000 0.000000 0.393469
1e15 0.000000 0.000000 0.000500
1e18 0.000000 0.000000 0.000001

碰撞機率

生日悖論

其實只要23個人,某兩人同天生日機率就大於一半了

什麼是碰撞?

string A, B;
cin >> A >> B;

if (A == B) { // O(n)
	cout << "YES\n";
} else {
	cout << "NO\n";
}
O(n)
string A, B;
cin >> A >> B;

// precalculate hash value in O(n)
int a = A.getHash(), b = B.getHash();
if (a == b) { // O(1)
	cout << "YES\n";
} else {
	cout << "NO\n";
}
O(1)

What for ?

比較兩個東西是否一樣

O(1)

如果哈希值一樣

-> 可能不一樣

如果哈希值不一樣

-> 一定不一樣

Monte Carlo

What for ?

比較兩個東西是否一樣

string A, B;
cin >> A >> B;

// O(n) get hash value
int a = A.getHash(), b = B.getHash();
if (a == b) { // O(1)
	cout << "YES\n";
} else {
	cout << "NO\n";
}
(s[0]A^{n-1} + s[1]A^{n-2} + \cdots + s[n-1]A^{0}) \mod B

多項式 Hashing

A跟B怎麼決定?

A=2593 B=172 ?

然後你就會發現這樣"keaucucal"跟"cjtsai"是同個hash value欸

那所以就

挑個質數

不然就來

RANDOM 囉

就不會被暴力碰撞了

(s[0]A^{n-1} + s[1]A^{n-2} + \cdots + s[n-1]A^{0}) \mod B

多項式 Hashing

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct RandomizedHash {
	vector<ll> hash, power; // 哈希值前綴和 / 紀錄Base冪次 
	ll MOD, BASE; // B / A

	RandomizedHash(const string &s) {
		mt19937 rng(807); // 設定random number generator的種子為807
		uniform_int_distribution<> dist(257, 1e9 + 7); // 設定範圍為 257 ~ 1000000007
		MOD = dist(rng); // 隨機設定B
		BASE = dist(rng); // 隨機設定A

		int n = s.size();
		hash.resize(n + 1, 0);
		power.resize(n + 1, 1);

		for (int i = 0; i < n; i++) {
			hash[i + 1] = (hash[i] * BASE + s[i]) % MOD;
			power[i + 1] = (power[i] * BASE) % MOD;
		}
	}

	ll getHash(int l, int r) {
		// 取得l ~ r 子字串的哈希值
		return (hash[r + 1] - hash[l] * power[r - l + 1] % MOD + MOD) % MOD;
	}
};

int main() {
	string input;
	cout << "Enter a string: ";
	getline(cin, input);
	RandomizedHash hasher(input);

	cout << "Hash of the entire string: " << hasher.getHash(0, input.length() - 1) << endl;
}

題目

找出字符串的所有週期長度

可以通過重複那一個前綴來生成整個字串

 = 找出有幾個前綴,

給你N個字串

M個詢問

問你第M個字串在N個裡面重複幾個

575919122

沒了 你猜到這是什麼的Hash Value我請你喝飲料

更:答案是807sodian 被猜出來了

Random

By keaucucal

Random

We've added support for incredibly smooth animations between code blocks. See it in action in this deck!

  • 338