void swap(int& a, int& b){
int tmp = a;
a = b;
b = tmp;
}
void shuffle(int* arr, int n){
if(n < 1)
return;
srand(time(NULL));
for(int i = 0; i < n; i++){
int tmp_idx = (rand() % (n - i) + i);
swap(arr[i], arr[tmp_idx]);
}
}
证明:不考虑数组中元素是否重复,长度为n的数组,其全排列共有 n ! n! n!中。要做到概率上的随机打乱,那么打乱后排列的概率需要是 1 n ! \frac{1}{n!} n!1。在for循环的第k次迭代后,对每个可能的k排列,子数组arr[1,k]包含这k个排列的概率是 ( n − k ) ! n ! \frac{(n-k)!}{n!} n!(n−k)!。下面用数学归纳法证明循环不等式成立:
(1)当k=1时,第一个元素的概率是 1 n \frac{1}{n} n1,循环不等式 ( n − 1 ) ! n ! = 1 n \frac{(n-1)!}{n!}=\frac{1}{n} n!(n−1)!=n1,循环不等式成立;
(2)假设当k=m时,循环不等式也成立;则当k=m+1时,k排列的概率=(k-1)排列的概率 * 第k个元素的概率。即 ( n − m ) ! n ! ∗ 1 n − m = ( n − m − 1 ) ! n ! = ( n − ( m + 1 ) ) ! n ! \frac{(n-m)!}{n!}*\frac{1}{n-m}=\frac{(n-m-1)!}{n!}=\frac{(n-(m+1))!}{n!} n!(n−m)!∗n−m1=n!(n−m−1)!=n!(n−(m+1))!,循环不等式成立;
(3)所以,当k=n时, ( n − ( n − 1 ) ) ! n ! ∗ 1 n − ( n − 1 ) = 1 n ! \frac{(n-(n-1))!}{n!}*\frac{1}{n-(n-1)}= \frac{1}{n!} n!(n−(n−1))!∗n−(n−1)1=n!1,问题得证。
double mySqrt(double x){
double eps = 1e-8;
if (x < 0)
return -1.0;
if (x <= eps || (x - 1) <= eps)
return x;
double l = 1.0, r = x;
double mid = l + (r - l) / 2.0;
double res = mid * mid - x;
while (abs(res) > eps){
if (res > 0)
r = mid;
else
l = mid;
mid = l + (r - l) / 2.0;
res = mid * mid - x;
}
return mid;
}
解法二:牛顿法。要求解sqrt(x),即就是求 f ( x ) = x 2 − t = 0 f(x)=x^2-t=0 f(x)=x2−t=0的解。假设初始解为 x 0 x_0 x0,那么我们在点 ( x 0 , f ( x 0 ) ) (x_0,f(x_0)) (x0,f(x0))的切线方程为 y − f ( x 0 ) = f ′ ( x 0 ) ( x − x 0 ) y-f(x_0)=f'(x_0)(x-x_0) y−f(x0)=f′(x0)(x−x0);令 y = 0 y=0 y=0得到 x = x 0 2 + t 2 x 0 x=\frac{x_0}{2}+\frac{t}{2x_0} x=2x0+2x0t,则迭代解为 x n = x n − 1 2 + t 2 x n − 1 x_{n}=\frac{x_{n-1}}{2}+\frac{t}{2x_{n-1}} xn=2xn−1+2xn−1t。若 f ( x n ) f(x_n) f(xn)很接近与0,那么 x n x_n xn即为要求的解。如下图所示:
double mySqrt(double x){
double eps = 1e-8;
if (x < 0)
return -1.0;
if (x <= eps || (x - 1) <= eps)
return x;
double x0 = x, t = x;
x0 = x0 / 2 + t / (2 * x0);
while (abs(x0 * x0 - t) > eps)
x0 = x0 / 2 + t / (2 * x0);
return x0;
}
def my_conv(input_feature, kernel):
input_rows, input_cols, input_channels = input_feature.shape
kernel_size, _, output_channels = kernel.shape
output_rows = input_rows - kernel_size + 1
output_cols = input_cols - kernel_size + 1
output_features = np.zeros([output_rows, output_cols, output_channels], dtype=np.float32)
for c in range(output_channels):
for i in range(output_rows):
for j in range(output_cols):
output_features[i, j, c] = compute_conv(input_feature[i:i + kernel_size, j:j + kernel_size, :],
kernel[:, :, c])
return output_features
def compute_conv(input_block, single_kernel):
res = 0
for in_c in range(input_block.shape[2]):
res += (input_block[:, :, in_c] * single_kernel).sum()
return res
def isInside(x1, y1, x2, y2, x3, y3, x4, y4, x, y):
def isInside(x1, y1, x4, y4, x, y):
if x <= x1 or x >= x4 or y >= y1 or y <= y4:
return false
return true
if y1 == y2: ##矩阵平行于坐标轴
return isInside(x1, y1, x4, y4, x, y)
a = abs(y4 - y3)
b = abs(x4 - x3)
c = math.sqrt(a**2 + b**2)
sin_theta = a / c;
cos_theta = b / c;
x1_hat = x1 * cos_theta + y1 * sin_theta ##注意旋转了-theta
y1_hat = -x1 * sin_theta + y1 * cos_theta
x4_hat = x4 * cos_theta + y4 * sin_theta
y4_hat = -x4 * sin_theta + y4 * cos_theta
x_hat = x * cos_theta + y * sin_theta
y_hat = -x * sin_theta + y * cos_theta
return isInside(x1_hat, y1_hat, x4_hat, y4_hat, x_hat, y_hat)
int reachNumber(int target){
target = abs(target);
int step = 0, sum = 0;
while(sum < target || (sum - target) % 2 == 1)
sum += (++step);
return step;
}
int pickOne(vector& file){
if(file.empty()) return -1;
srand(time(NULL));
int pre_picked = file[0];
for(int L = 1; L < file.size(); L++)
if(rand() % L == 0)
pre_picked = file[L];
return pre_picked;
}
四个人过河,过河用时分别为1,2,5,8,每次只能过两个人,同时要有人把手电筒送回来,问最短多长时间能过完?
解:(1)1,2过去,1回来,3分钟;(2)5,8过去,2回来,10分钟;(3)1,2过去,2分钟。因此最短时间为3+10+2=15分钟。
一个半径为R的圆用一些半径为R/2的圆去覆盖,至少要用多少才能完全覆盖?
解:要最少,则覆盖率最高,在不剪碎的前提下讨论。如要完全覆盖,则必须完全覆盖大圆的圆周,于是小圆的利用率越高,与大圆交点解得的弦长越长。令大圆与小圆交点截得的弦长最长为小圆直径,即弦长=R,则弦至大圆圆心的距离为 3 2 R > 1 2 R \frac{\sqrt 3}{2}R>\frac{1}{2}R 23R>21R,所以中间不能完全覆盖,还要加一个。
综上,单个小圆覆盖的角度是60度,因此总共需要6+1=7个小圆。
从1-12中至少选出几个数字,可以保证其中有两个数的差为7?从1-12中至少选出几个数字,可以保证其中有两个数的差为4?
解:典型的抽屉思想。(1)差为7的数组有:(1,8)(2,9)(3,10)(4,11)(5,12)。从这五组里一组里拿一个,再加上多出来的6,7,也就是5+2,然后再随便拿一个就可以了,所以是5+2+1=8;(2)差为4的数组有:(1,5,9)(2,6,10)(3,7,11)(4,8,12),。从这五组里分别取出两边的数字,总共是8个,然后从剩下的4个里拿一个就可以了。所以是4+4+1=9。
甲乙丙丁四人进行传球训练,要求每人接球后传给其他任何一个人,开始由甲发球,作为第一次传球,问第五次传回甲的传法有多少种?
解:共有60种。因为第四次传球不能传给甲,所以本题要分情况讨论:
把280张卡片分给若干名同学,每人都要分到,但都不得超过10张。证明:至少有6位同学得到的卡片数目同样多。
解:每个同学得到的卡片个数不超过10张,因此每个同学卡片个数都有10种可能。如果10个同学都不重复,则每组10人共分了1+2+3+…+10=55张卡片。由 280 / 55 = 5 , 280 % 55 = 5 280/55=5,280\%55=5 280/55=5,280%55=5得,分成这样的5组还剩5张,每种张数都有5个同学一样,因此剩下的5张无论如何分配,必然与前面5组中某种张数相同,此时这种张数有6名同学。
有个红绿灯路口,统计从这个红绿灯路口经过的车辆,他们的等车时间(大于等于0),把等车时间存成一个数组,问,红绿灯的时长分别是多少?
解:当统计数组足够长的时候,数组的最大值就可以近似是红灯的时间(意味着车辆刚来的时候就是红灯,整整等了一个红灯的时间);然后统计数组中0出现的次数(代表绿灯(没等)的车辆数),以及非零数字出现的次数(代表红灯(等了)的车辆数),还是当数组足够长的时候,没等的车辆数 / 等了的车辆数这个比值就是红绿灯的时长比值,由于红灯的时间已经算出来了,因此,绿灯的时间也可以算出来。
将一根木棍分成三段,求这三段构成三角形的概率
在一圆周上任意取三个点构成锐角三角形的概率是多少
两个题的答案参考这篇博客。
-----------------------------2019.9.20 补充--------------------------------------
总结:【参考】
组成锐角的概率:1/4
组成钝角的概率:3/4
组成直角的概率:0
这时,根据圆周角与所夹弧长的关系可以把该问题转化为几何概型:
三角形为锐角三角形的充要条件是三条弧长都小于π ;
三角形为直角三角形的充要条件是三条弧长只有一条等于π ;
三角形为钝角三角形的充要条件是三条弧长只有一条大于π。
将几何概型表现在坐标轴上:
其中,ΔAOB 的所围成区域的点集表示了全概率空间, S 3 S_3 S3 表示组成锐角三角形的事件,根据面积比可以得到概率为 S 3 S Δ A O B = 1 4 \frac{S_3}{S_{\Delta AOB}}=\frac{1}{4} SΔAOBS3=41 ; 而三条红线在ΔAOB 中所截断线段的长度代表组成直角三角形的事件,其概率为0;S1+S2+S4 表示组成钝角三角形的事件,其概率为 3 4 \frac{3}{4} 43
n个人,每个人都不在自己位置上的组合数——全错位排列
【参考】
设长度为n的序列的全错位排列一共有f(n)种,假设我们已经解决了f(1)到f(n-1),那么当序列新增了一个元素an,显然全错位排列中该元素不能放在第n个位置上,假设该元素在从1到n-1的第i个位置,那么在新序列中第n个位置上的元素可能有两种情况:
(1)第n个位置上的元素为ai
因为an和ai都不在原位置上,因此只需剩余的元素都是全错位排列,新序列就构成了全错位排列。那么除去ai和an还剩下n-2个元素,则这n-2个元素一共有f(n-2)种全错位排列,因为i的选择共有n-1种,因此该情况下一共有(n-1)*f(n-2)
种全错位排列。
(2) 第n个位置上的元素不为ai
该种情况相当于,前n-1个元素做好了全错位排列,an与其中任意元素交换位置,新生成的序列也是一个全错位排列。这种情况下i的选择共有n-1种,n-1的元素的全错位排列共有f(n-1)种,因此该情况下一共有(n-1)*f(n-1)
种全错位排列。
(总结) 综合以上两种情况,f(n)=(n-1)f(n-2)+(n-1)*f(n-1)=(n-1)[f(n-2)+f(n-1)]
显然这个公式适用于n>2的情况,而f(1)=0,f(2)=1是之前已经列举得出的。
将n=3代入,得到f(3)=2*(0+1)=2,将n=4代入,得到f(4)=3*(1+2)=9,与列举所得到的结果相同。
随机游走问题
(1)一维数轴上的随机游走
(1.1)回到原点的步数期望
(个人的理解,不一定对)假设随机变量X表示回到原点所需步数,则有P(X=奇数)=0,P(X=2)=1/2,P(X=4)=3/4,P(X=6)=5/16…,则E(X) = …
(1.2)n步之后回到原点,一共有多少种游走方案?
解法(动态规划):借鉴圆环上的随机游走问题,假设d(k,j)表示从点j 走k步到达原点0的方法数,则递推式为:
d(k, j) = d(k-1, j-1) + d(k-1, j+1)
(2)圆上的随机游走
一个从0-9的圆环,从0开始出发,可以顺时针或逆时针走,请问走n步回到0有几种不同的走法?
解法(动态规划):n步回到原点,有两种情况,n-1步到了1或者到了9,所以可以使用动态规划的思想,假设d(k, j)表示从点j 走k步到达原点0的方法数, 因此可以转化为他相邻的点经过k-1步回到原点的问题,这样将问题的规模缩小写出递推式:(求余是为了防止超出范围)
d(k, j) = d(k-1, (j-1+n)%n) + d(k-1, (j+1)%n);