提交 423cb588 编写于 作者: GreyZeng's avatar GreyZeng

move to pkg

上级 15dabdd0
package snippet;
//蓄水池算法
//解决的问题:
//假设有一个源源吐出不同球的机器,
//只有装下10个球的袋子,每一个吐出的球,要么放入袋子,要么永远扔掉
//如何做到机器吐出每一个球之后,所有吐出的球都等概率被放进袋子里
// 解法:
// 吐出1到10号球,完全入袋
// 引入随机函数f(i),提供一个值i,等概率返回1-i的一个数字
// 当K号球吐出的时候(K>10) ,我们通过以下决策决定是否要入袋
// 1) 10/K的概率决定球是否入袋 f(K) -> 如果返回10以内的数,则入袋,如果返回10以外的数,则扔掉
// 2) 第一步中如果决定入袋,那么袋子中已经存在的球以等概率丢弃一个。
// TODO 证明
//假设吐出了17号球,3号球在袋中的概率
//
// ```
// 1 * (1- 10/11 * 1/10) * (1 - 10/12 * 1/10) *....(1 - 10/17 * 1/10) = 10/17
// ```
// 用处
// (10亿个抽100)
// 一台服务器 放100个用户
// 用户检查是否是首次登录
// 用户是第几个登录的用户
// 如果非首次登录,直接丢弃,如果首次登录,那么以第100/N概率选中
// 分布式蓄水池算法使用:https://www.jianshu.com/p/7a9ea6ece2af
// ## 相关习题
//
//LeetCode_0398_RandomPickIndex.java
//
//LeetCode_0382_LinkedListRandomNode.java
//
//LeetCode_0692_TopKFrequentWords.java
//
//NowCoder_Bitorrent.java
//
//## UUID全局唯一生成器
//
//base + 各区域的服务器 range + base 最小值+range 压力被range分散掉
public class Code_0058_ReservoirSampling {
public static class RandomBox {
private int[] bag;
// 袋子容量
private int capacity;
// 第几号球
private int count;
public RandomBox(int capacity) {
bag = new int[capacity];
this.capacity = capacity;
count = 0;
}
// 随机函数,等概率生成1-max之间随机的一个数字
// Math.random() -> 生成[0,1)范围内的数
// (int)i 是对i进行向下取整
private int rand(int max) {
return (int) (Math.random() * max) + 1;
}
public void add(int num) {
// 球个数增加
count++;
// 如果球的个数没有超过容量
if (count <= capacity) {
// 则入袋
bag[count - 1] = num;
} else if (rand(count) <= capacity) {
// 否则以N/count的概率入袋
bag[rand(capacity) - 1] = num;
}
}
// 返回袋子中最终选中的球
public int[] choices() {
int[] res = new int[capacity];
System.arraycopy(bag, 0, res, 0, capacity);
return res;
}
}
public static void main(String[] args) {
System.out.println("hello");
int all = 100;
int choose = 10;
RandomBox box = new RandomBox(choose);
for (int num = 1; num <= all; num++) {
box.add(num);
}
int[] ans = box.choices();
for (int i = 0; i < ans.length; i++) {
System.out.println(i + " times : " + ans[i]);
}
}
}
package snippet;
// TODO
// 同时支持范围增加 + 范围修改 + 范围查询的动态开点线段树(累加和)
// 真的用到!才去建立
// 懒更新,及其所有的东西,和普通线段树,没有任何区别!
public class Code_0121_DynamicSegmentTree {
public static class Node {
public int sum;
public int lazy;
public int change;
public boolean update;
public Node left;
public Node right;
}
public static class DynamicSegmentTree {
public Node root;
public int size;
public DynamicSegmentTree(int max) {
root = new Node();
size = max;
}
private void pushUp(Node c) {
c.sum = c.left.sum + c.right.sum;
}
private void pushDown(Node p, int ln, int rn) {
if (p.left == null) {
p.left = new Node();
}
if (p.right == null) {
p.right = new Node();
}
if (p.update) {
p.left.update = true;
p.right.update = true;
p.left.change = p.change;
p.right.change = p.change;
p.left.lazy = 0;
p.right.lazy = 0;
p.left.sum = p.change * ln;
p.right.sum = p.change * rn;
p.update = false;
}
if (p.lazy != 0) {
p.left.lazy += p.lazy;
p.right.lazy += p.lazy;
p.left.sum += p.lazy * ln;
p.right.sum += p.lazy * rn;
p.lazy = 0;
}
}
public void update(int s, int e, int v) {
update(root, 1, size, s, e, v);
}
private void update(Node c, int l, int r, int s, int e, int v) {
if (s <= l && r <= e) {
c.update = true;
c.change = v;
c.sum = v * (r - l + 1);
c.lazy = 0;
} else {
int mid = (l + r) >> 1;
pushDown(c, mid - l + 1, r - mid);
if (s <= mid) {
update(c.left, l, mid, s, e, v);
}
if (e > mid) {
update(c.right, mid + 1, r, s, e, v);
}
pushUp(c);
}
}
public void add(int s, int e, int v) {
add(root, 1, size, s, e, v);
}
private void add(Node c, int l, int r, int s, int e, int v) {
if (s <= l && r <= e) {
c.sum += v * (r - l + 1);
c.lazy += v;
} else {
int mid = (l + r) >> 1;
pushDown(c, mid - l + 1, r - mid);
if (s <= mid) {
add(c.left, l, mid, s, e, v);
}
if (e > mid) {
add(c.right, mid + 1, r, s, e, v);
}
pushUp(c);
}
}
public int query(int s, int e) {
return query(root, 1, size, s, e);
}
private int query(Node c, int l, int r, int s, int e) {
if (s <= l && r <= e) {
return c.sum;
}
int mid = (l + r) >> 1;
pushDown(c, mid - l + 1, r - mid);
int ans = 0;
if (s <= mid) {
ans += query(c.left, l, mid, s, e);
}
if (e > mid) {
ans += query(c.right, mid + 1, r, s, e);
}
return ans;
}
}
public static class Right {
public int[] arr;
public Right(int size) {
arr = new int[size + 1];
}
public void add(int s, int e, int v) {
for (int i = s; i <= e; i++) {
arr[i] += v;
}
}
public void update(int s, int e, int v) {
for (int i = s; i <= e; i++) {
arr[i] = v;
}
}
public int query(int s, int e) {
int sum = 0;
for (int i = s; i <= e; i++) {
sum += arr[i];
}
return sum;
}
}
public static void main(String[] args) {
int n = 1000;
int value = 50;
int createTimes = 5000;
int operateTimes = 5000;
System.out.println("测试开始");
for (int i = 0; i < createTimes; i++) {
int size = (int) (Math.random() * n) + 1;
DynamicSegmentTree dst = new DynamicSegmentTree(size);
Right right = new Right(size);
for (int k = 0; k < operateTimes; k++) {
double choose = Math.random();
if (choose < 0.333) {
int a = (int) (Math.random() * size) + 1;
int b = (int) (Math.random() * size) + 1;
int s = Math.min(a, b);
int e = Math.max(a, b);
int v = (int) (Math.random() * value);
dst.update(s, e, v);
right.update(s, e, v);
} else if (choose < 0.666) {
int a = (int) (Math.random() * size) + 1;
int b = (int) (Math.random() * size) + 1;
int s = Math.min(a, b);
int e = Math.max(a, b);
int v = (int) (Math.random() * value);
dst.add(s, e, v);
right.add(s, e, v);
} else {
int a = (int) (Math.random() * size) + 1;
int b = (int) (Math.random() * size) + 1;
int s = Math.min(a, b);
int e = Math.max(a, b);
int ans1 = dst.query(s, e);
int ans2 = right.query(s, e);
if (ans1 != ans2) {
System.out.println("出错了!");
System.out.println(ans1);
System.out.println(ans2);
}
}
}
}
System.out.println("测试结束");
}
}
package snippet;
package 数据结构.动态开点线段树;
// TODO
// 只支持单点增加 + 范围查询的动态开点线段树(累加和)
// tips:
public class Code_0120_DynamicSegmentTree {
public class Code_DynamicSegmentTree1 {
public static class Node {
public int sum;
......
package 数据结构.动态开点线段树;
// TODO
// 同时支持范围增加 + 范围修改 + 范围查询的动态开点线段树(累加和)
// 真的用到!才去建立
// 懒更新,及其所有的东西,和普通线段树,没有任何区别!
public class Code_DynamicSegmentTree2 {
public static class Node {
public int sum;
public int lazy;
public int change;
public boolean update;
public Node left;
public Node right;
}
public static class DynamicSegmentTree {
public Node root;
public int size;
public DynamicSegmentTree(int max) {
root = new Node();
size = max;
}
private void pushUp(Node c) {
c.sum = c.left.sum + c.right.sum;
}
private void pushDown(Node p, int ln, int rn) {
if (p.left == null) {
p.left = new Node();
}
if (p.right == null) {
p.right = new Node();
}
if (p.update) {
p.left.update = true;
p.right.update = true;
p.left.change = p.change;
p.right.change = p.change;
p.left.lazy = 0;
p.right.lazy = 0;
p.left.sum = p.change * ln;
p.right.sum = p.change * rn;
p.update = false;
}
if (p.lazy != 0) {
p.left.lazy += p.lazy;
p.right.lazy += p.lazy;
p.left.sum += p.lazy * ln;
p.right.sum += p.lazy * rn;
p.lazy = 0;
}
}
public void update(int s, int e, int v) {
update(root, 1, size, s, e, v);
}
private void update(Node c, int l, int r, int s, int e, int v) {
if (s <= l && r <= e) {
c.update = true;
c.change = v;
c.sum = v * (r - l + 1);
c.lazy = 0;
} else {
int mid = (l + r) >> 1;
pushDown(c, mid - l + 1, r - mid);
if (s <= mid) {
update(c.left, l, mid, s, e, v);
}
if (e > mid) {
update(c.right, mid + 1, r, s, e, v);
}
pushUp(c);
}
}
public void add(int s, int e, int v) {
add(root, 1, size, s, e, v);
}
private void add(Node c, int l, int r, int s, int e, int v) {
if (s <= l && r <= e) {
c.sum += v * (r - l + 1);
c.lazy += v;
} else {
int mid = (l + r) >> 1;
pushDown(c, mid - l + 1, r - mid);
if (s <= mid) {
add(c.left, l, mid, s, e, v);
}
if (e > mid) {
add(c.right, mid + 1, r, s, e, v);
}
pushUp(c);
}
}
public int query(int s, int e) {
return query(root, 1, size, s, e);
}
private int query(Node c, int l, int r, int s, int e) {
if (s <= l && r <= e) {
return c.sum;
}
int mid = (l + r) >> 1;
pushDown(c, mid - l + 1, r - mid);
int ans = 0;
if (s <= mid) {
ans += query(c.left, l, mid, s, e);
}
if (e > mid) {
ans += query(c.right, mid + 1, r, s, e);
}
return ans;
}
}
public static class Right {
public int[] arr;
public Right(int size) {
arr = new int[size + 1];
}
public void add(int s, int e, int v) {
for (int i = s; i <= e; i++) {
arr[i] += v;
}
}
public void update(int s, int e, int v) {
for (int i = s; i <= e; i++) {
arr[i] = v;
}
}
public int query(int s, int e) {
int sum = 0;
for (int i = s; i <= e; i++) {
sum += arr[i];
}
return sum;
}
}
public static void main(String[] args) {
int n = 1000;
int value = 50;
int createTimes = 5000;
int operateTimes = 5000;
System.out.println("测试开始");
for (int i = 0; i < createTimes; i++) {
int size = (int) (Math.random() * n) + 1;
DynamicSegmentTree dst = new DynamicSegmentTree(size);
Right right = new Right(size);
for (int k = 0; k < operateTimes; k++) {
double choose = Math.random();
if (choose < 0.333) {
int a = (int) (Math.random() * size) + 1;
int b = (int) (Math.random() * size) + 1;
int s = Math.min(a, b);
int e = Math.max(a, b);
int v = (int) (Math.random() * value);
dst.update(s, e, v);
right.update(s, e, v);
} else if (choose < 0.666) {
int a = (int) (Math.random() * size) + 1;
int b = (int) (Math.random() * size) + 1;
int s = Math.min(a, b);
int e = Math.max(a, b);
int v = (int) (Math.random() * value);
dst.add(s, e, v);
right.add(s, e, v);
} else {
int a = (int) (Math.random() * size) + 1;
int b = (int) (Math.random() * size) + 1;
int s = Math.min(a, b);
int e = Math.max(a, b);
int ans1 = dst.query(s, e);
int ans2 = right.query(s, e);
if (ans1 != ans2) {
System.out.println("出错了!");
System.out.println(ans1);
System.out.println(ans2);
}
}
}
}
System.out.println("测试结束");
}
}
package 算法.蓄水池算法;
// 蓄水池算法
// 解决的问题:
// 假设有一个源源吐出不同球的机器,
// 只有装下10个球的袋子,每一个吐出的球,要么放入袋子,要么永远扔掉
// 如何做到机器吐出每一个球之后,所有吐出的球都等概率被放进袋子里
// 解法:
// 吐出1到10号球,完全入袋
// 引入随机函数f(i),提供一个值i,等概率返回1-i的一个数字
// 当K号球吐出的时候(K>10) ,我们通过以下决策决定是否要入袋
// 1) 10/K的概率决定球是否入袋 f(K) -> 如果返回10以内的数,则入袋,如果返回10以外的数,则扔掉
// 2) 第一步中如果决定入袋,那么袋子中已经存在的球以等概率丢弃一个。
// TODO 证明
// 假设吐出了17号球,3号球在袋中的概率
//
// ```
// 1 * (1- 10/11 * 1/10) * (1 - 10/12 * 1/10) *....(1 - 10/17 * 1/10) = 10/17
// ```
// 用处
// (10亿个抽100)
// 一台服务器 放100个用户
// 用户检查是否是首次登录
// 用户是第几个登录的用户
// 如果非首次登录,直接丢弃,如果首次登录,那么以第100/N概率选中
// 分布式蓄水池算法使用:https://www.jianshu.com/p/7a9ea6ece2af
// ## 相关习题
//
// LeetCode_0398_RandomPickIndex.java
//
// LeetCode_0382_LinkedListRandomNode.java
//
// LeetCode_0692_TopKFrequentWords.java
//
// NowCoder_Bitorrent.java
//
// ## UUID全局唯一生成器
//
// base + 各区域的服务器 range + base 最小值+range 压力被range分散掉
public class Code_ReservoirSampling {
public static class RandomBox {
private int[] bag;
// 袋子容量
private int capacity;
// 第几号球
private int count;
public RandomBox(int capacity) {
bag = new int[capacity];
this.capacity = capacity;
count = 0;
}
// 随机函数,等概率生成1-max之间随机的一个数字
// Math.random() -> 生成[0,1)范围内的数
// (int)i 是对i进行向下取整
private int rand(int max) {
return (int) (Math.random() * max) + 1;
}
public void add(int num) {
// 球个数增加
count++;
// 如果球的个数没有超过容量
if (count <= capacity) {
// 则入袋
bag[count - 1] = num;
} else if (rand(count) <= capacity) {
// 否则以N/count的概率入袋
bag[rand(capacity) - 1] = num;
}
}
// 返回袋子中最终选中的球
public int[] choices() {
int[] res = new int[capacity];
System.arraycopy(bag, 0, res, 0, capacity);
return res;
}
}
public static void main(String[] args) {
System.out.println("hello");
int all = 100;
int choose = 10;
RandomBox box = new RandomBox(choose);
for (int num = 1; num <= all; num++) {
box.add(num);
}
int[] ans = box.choices();
for (int i = 0; i < ans.length; i++) {
System.out.println(i + " times : " + ans[i]);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册