一、數字組合
給定一個數組a,其中元素各不相同且都是0~9之間的數字。
給定一個數字n,要求用數組a中的數字組合出一個大於n的十進制數字來,要求組合出來的數字盡量小,數組a中的元素可以使用多次。
思路
從高位往低位掃一遍,貪心使用最小值,如果使用了較大值,剩下的低位一律用最小值進行填充。
如果找不到合適的,需要回溯使用更大的填充。一旦使用更大的填充之后,剩下的低位使用最小值填充。
題目中要求組合出大於n的十進制數來,如果最后貪心出來的結果等於n,同樣需要回溯一遍。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class Main {
Random r = new Random(0);
int[] generate() {
int[] b = new int[10];
for (int i = 0; i < b.length; i++) b[i] = i;
for (int i = 0; i < b.length; i++) {
int nex = r.nextInt(b.length - i) + i;
int temp = b[i];
b[i] = b[nex];
b[nex] = temp;
}
return Arrays.copyOf(b, r.nextInt(5) + 2);
}
List<Integer> parse(int n) {
List<Integer> a = new ArrayList<>(11);
while (n > 0) {
a.add(n % 10);
n /= 10;
}
for (int i = 0; i < a.size() / 2; i++) {
int temp = a.get(i);
a.set(i, a.get(a.size() - 1 - i));
a.set(a.size() - 1 - i, temp);
}
return a;
}
int upperEq(int[] a, int x) {
int l = 0, r = a.length;
while (l + 1 < r) {
int mid = (l + r) >> 1;
if (a[mid] < x) {
l = mid + 1;
} else if (a[mid] >= x) {
r = mid;
}
}
if (l < a.length && a[l] >= x) r = l;
if (r == a.length) return -1;
return a[r];
}
int upper(int[] a, int x) {
int l = 0, r = a.length;
while (l + 1 < r) {
int mid = (l + r) >> 1;
if (a[mid] <= x) {
l = mid;
} else if (a[mid] > x) {
r = mid;
}
}
if (r == a.length) return -1;
return a[r];
}
int pack(List<Integer> a) {
int s = 0;
for (int i : a) s = s * 10 + i;
return s;
}
int solve(int a[], int n) {
if (a.length == 0) return -1;
if (a.length == 1 && a[0] == 0) return -1;
Arrays.sort(a);
int first = a[0] == 0 ? a[1] * 10 : a[0] * 10 + a[0];
List<Integer> bits = parse(n);
List<Integer> ans = new ArrayList<>(bits);
//從高位向低位走一遍,如果找到大值,剩余位直接使用最小值填充
boolean flag = false;
int i = 0;
for (; i < bits.size(); i++) {
//沒有找到大值,使用最小上界
int x = upperEq(a, bits.get(i));
if (x == -1) {
break;
}
ans.set(i, x);
if (x != bits.get(i)) {
flag = true;
i++;
break;
}
}
//如果沒能成功使用大值填充,需要回溯
if (!flag) {
for (i = Math.min(bits.size() - 1, i); i >= 0; i--) {
int x = upper(a, bits.get(i));
if (x == -1 && i == 0) {
x = first;
}
if (x != -1) {//成功找到了大值,可以跳出了
ans.set(i, x);
i++;
break;
}
}
}
for (; i < bits.size(); i++) {
ans.set(i, a[0]);//使用最小值進行填充
}
return pack(ans);
}
Main() {
for (int i = 0; i < 10; i++) {
int[] a = generate();
int n = r.nextInt(10000000);
System.out.println(Arrays.toString(a) + " " + n + " " + solve(a, n));
}
}
public static void main(String[] args) {
new Main();
}
}
二、max(x,y)的期望
已知x和y都是0到1上的均勻分布,求max(x,y)的期望。
下面這種方法只能算是湊對的。
$\int_{0}^{1} 1-m^2 dm=\frac{2}{3}$
$m^2$表示當x<m
且x<m
的概率,用1減去它表示max(x,y)不小於m的概率。
正經方法如下:
先求概率分布,再求概率密度函數
$P(max(x,y)<z)=P(x<z)\times P(y<z)=z^2$
求導的到概率密度函數$f(z)=2z$
求積分的到期望$E(z)=\int_0^1 f(z)z dz=\int_0^1 \frac{2z^2}{3}=\frac{2}{3}$
真是忘得一干二凈了
import java.util.*;
import java.util.stream.Collectors;
public class Main {
Random r = new Random(0);
Main() {
double s = 0;
int cnt = 0;
for (int i = 0; i < 10000; i++) {
double x = r.nextDouble(), y = r.nextDouble();
s += Math.max(x, y);
cnt++;
}
System.out.println(s / cnt);
}
public static void main(String[] args) {
new Main();
}
}