Skip to content

蓄水池抽样算法(Reservoir Sampling)

给定一个数据流,数据流长度N很大,且N直到处理完所有数据之前都不可知,请问如何在只遍历一遍数据(O(N))的情况下,能够随机选取出K个不重复的数据。

int[] result = new int[K];
for (int i = 0; i < K; i++) { // 前 K 个元素直接放入数组中
 	result[i] = pool[i];
}

for (int i = K; i < N; i++) { // K + 1 个元素开始进行概率采样
  int r = random.nextInt(i + 1);
  if (r < K) {
 	 result[r] = pool[i];
  }
}

最大公约数,最小公倍数

求最小公倍数需要最大公约数

// 最小公倍数
private long lcm(long a, long b) {
	return a * b / gcd(a, b);
}
    
// 最大公约数
private long gcd(long x, long y) {
  if (x == 0) return y;
  return gcd(y % x, x);
}

枚举二进制子集

// m => 总状态数
for (int i = 1; i < m; i++) {
    // 枚举状态 i 的二进制子集
    for (int j = i; j > 0; j = (j - 1) & i) {
        // To Do..
    }
}

最长上升子序列(Longest Increasing Subsequence)

// 动态规划 O(n2)
public int lengthOfLIS(int[] nums) {
    if (nums == null || nums.length == 0) {
    		return 0;
    }
    int[] dp = new int[nums.length];
    // 最小值都为1
    Arrays.fill(dp, 1);

    int max = 0;
    // 遍历前面的所以数字
    for (int i = 1; i < nums.length; i++) {
        for (int j = 0; j < i; j++) {
          if (nums[j] < nums[i]) {
            // 当小于当前值时,取最大的数量
            dp[i] = Math.max(dp[i], dp[j] + 1);
            max = Math.max(max, dp[i]);
          }
        }
    }
    return max;
}



    // 二分 贪心 O(n*logn)
    public int lengthOfLIS(int[] nums) {
        int ans = 0;
        // 最长上升子序列(Longest  Increasing Subsequence)
        int[] lis = new int[nums.length];
        int index = 0;
        for (int num : nums) {
            if (index == 0) {
                // 初始化子序列
                lis[index++] = num;
                continue;
            }

            if (num > lis[index - 1]) {
                // 大于直接添加到尾部
                lis[index++] = num;
                continue;
            }


            // 二分找第一个大于当前值的索引
            int left = 0, right = index - 1;
            while (left < right) {
                // 找左边中位数
                int mid = (left + right) / 2;
                if (lis[mid] < num) {
                    // 继续找右边的
                    left = mid + 1;
                } else {
                    // 可能是目标
                    right = mid;
                }
            }

            // 替换掉
            lis[right] = num;
        }

        return index;
    }