27、随机算法
1、随机算法的简单分类
2、最基础的公平随机取样
public class Pick { private final Map<Integer, ArrayList<Integer>> map; private final Random random; public Pick(int[] nums) { random = new Random(); map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { int key = nums[i]; if (!map.containsKey(key)) map.put(key, new ArrayList<>()); map.get(key).add(i); } } public int pick(int target) { ArrayList<Integer> list = map.get(target); int size = list.size(); // return list.get(random.nextInt(size)); return list.get((int) (random.nextDouble() * size)); } }
3、加权随机取样
public class PickIndex { private final int[] presum; private final int sum; private final Random random; public PickIndex(int[] w) { // w[i] 代表第 i 个任务的权重, 也就是说, 应该给第 i 个任务发放 w[i] 张彩票 // 给每个任务发放彩票, 总共发了 sum(w[]) 张彩票 // 我们只需要记录每个任务的彩票区间就好了, 更近一步, 只需要记录每个任务第一张彩票的编号 // 因为下一个任务第一张彩票的编号 = 上一个任务最后一张彩票的编号 + 1 // presum[i] = 第 i 个任务第一张彩票的编号 presum = new int[w.length]; for (int i = 1; i < presum.length; i++) presum[i] = presum[i - 1] + w[i - 1]; sum = presum[w.length - 1] + w[w.length - 1]; random = new Random(); } public int pickIndex() { int x = random.nextInt(sum); // 二分查找 presum[i] <= x 的最大值对应的 i int l = 0; int r = presum.length - 1; int mid; while (l < r) { mid = l + (r - l + 1) / 2; if (presum[mid] <= x) l = mid; else r = mid - 1; } return l; } }
4、生成任意区间随机数
// 作业
5、拒绝采样
6、使用 rand7,实现 rand10
public class Rand10 { /** * 1 ~ 7 */ public int rand7() { return new Random().nextInt(7) + 1; } /** * 1 ~ 10 */ public int rand10() { while (true) { int a = rand7() - 1; // a in 0 ~ 6 int b = rand7() - 1; // b in 0 ~ 6 int t = a * 7 + b; // t in 0 ~ 48 if (t >= 40) continue; return t % 10 + 1; } } }
// 作业
7、多次采样和洗牌算法
8、KnuthShuffle
public class KnuthShuffle { private final int[] nums; private final Random random; public KnuthShuffle(int[] nums) { this.nums = nums.clone(); random = new Random(); } public int[] reset() { return nums.clone(); } /** * 从后向前决定排列中的每个元素 */ public int[] shuffle1() { int[] data = nums.clone(); for (int i = data.length - 1; i >= 0; i--) { int j = random.nextInt(i + 1); swap(data, i, j); } return data; } /** * 从前向后决定排列中的每个元素 */ public int[] shuffle2() { int[] data = nums.clone(); for (int i = 0; i < data.length; i++) { // random[i ... data.length - 1] = random[0 ... data.length - 1 - i] + i int j = random.nextInt(data.length - i) + i; swap(data, i, j); } return data; } private void swap(int[] arr, int a, int b) { int k = arr[a]; arr[a] = arr[b]; arr[b] = k; } }
9、蓄水池抽样
// 这个题目的接口不是很好 // Solution(int k) // void fetch(int newValue) // int[] sampling() public class GetRandom { private final ListNode head; private final Random random; public GetRandom(ListNode head) { this.head = head; random = new Random(); } /** * 蓄水池抽样, 蓄水池的大小为 1 */ public int getRandom() { int res = head.val; int index = 1; for (ListNode cur = head.next; cur != null; cur = cur.next, index++) { int j = random.nextInt(index + 1); if (j == 0) res = cur.val; } return res; } }
10、随机采样算法小节
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17333662.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步