import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
/**
* http://weibo.com/1915548291/z7HtOF4sx
* #面试题#有一个数组,每次从中间随机取一个,然后放回去,当所有的元素都被取过,返回总共的取的次数。
* 写一个函数实现。复杂度是什么。
*
* 我认为这道题的考点是如何节省空间。
* 当然可以用一个与原数组长度相同的数组来标记对应元素是否被取过,但这样太浪费空间
* 用bitmap的话,只要一个bit就可以标记是否被取过,可参考《编程珠玑》的位图排序
*
* 时间复杂度的话,我不太会算,以下是引用https://github.com/vyan/test/blob/master/accessTimes.cpp:
* 使用bit打点记录已经取的数,
* 复杂度分析,假设数组总长度为n
* 取到第1个之前未被取到的数的期望 E(1)=1
* 取到第2个之前未被取到的数的期望 E(2)=n/n-1
* 取到第3个之前未被取到的数的期望 E(3)=n/n-2
* ...
* 取到第n个之前未被取到的数的期望 E(n)=n/1
* 总得期望次数E=n+n/(n-1)+n/(n-2)+...+n/1;
* =n(1+1/(n-1)+1/(n-2)+...+1/1)
* =nln(n)
* 所以算法平均复杂度为nlogn
*
* 下面的代码里面,除法和求模运算我都用位运算来实现(为了练习位运算),事实上直接用java提供的(/,%)也可以
* 同时,为了验证是否真的取到了数组的所有元素,我用了TreeSet保存已选中的下标(去重)
*
* 最后,还有一个问题是,可能取了很多次,都没能全选中,这个时候可以设置一个最长时间或者最大尝试次数,超过则结束程序,
* 避免程序长时间运行甚至死循环
*
* @author lijinnan
*
*/
public class TimesOfAccessArray {
public static final int SHIFT = 5;
public static final int BLOCK_SIZE = (1 << SHIFT); //32
public static final int MASK = (1 << SHIFT) - 1; //31
public static void main(String[] args) {
int[] array = new int[200];
long times = accessTimes(array);
System.out.println(times);
}
public static long accessTimes(int[] array) {
if (array == null || array.length == 0) {
return -1L;
}
long result = 0L;
int len = array.length;
int[] bitmap = new int[divide(len, BLOCK_SIZE) + 1];
int setTimes = 0;
Set<Integer> set = new TreeSet<Integer>();
while (setTimes < len) {
int pos = new Random().nextInt(len);
set.add(pos);
if (set(bitmap, pos)) {
setTimes++;
}
result++;
}
System.out.println(set);
return result;
}
public static boolean set(int[] bitmap, int pos) {
boolean result = false;
int blockNo = divide(pos, BLOCK_SIZE);
int index = mod(pos, BLOCK_SIZE);
boolean notExist = (bitmap[blockNo] & (1 << index))== 0;
if (notExist) {
bitmap[blockNo] |= (1 << index);
result = true;
}
return result;
}
public static boolean exist(int[] bitmap, int pos) {
int blockNo = divide(pos, BLOCK_SIZE);
int index = mod(pos, BLOCK_SIZE);
return (bitmap[blockNo] & (1 << index)) != 0;
}
private static int divide(int x, int y) {
return x >> offSet(y);
}
private static int mod(int x, int y) {
int z = x;
int i = offSet(y);
return z - ((z >> i) << i);
}
//e.g. 32=2^5, return 5 只考虑2的幂
private static int offSet(int y) {
return howManyBits(y) - 1;
}
//二进制的表示里面,有多少位。例如32是6位
private static int howManyBits(int y) {
int bitNum = 0;
while (y != 0) {
y = (y >> 1);
bitNum++;
}
return bitNum;
}
}
分享到:
相关推荐
代码如下:[removed] <!– var test = [“aa”,”bb”,”cc”,”dd”,”ee”]; [removed](test[Math.floor(Math.random()*test.length...注意:[ ] 符号在javascript中定义一个数组,{ } 则定义一个对象 随机取得数组
标题 "现有1~100共一百个自然数,已随机放入一个有98个元素的数组a[98]" 暗示了一个编程问题,其中涉及到数组、随机数和计数算法。在这个问题中,我们需要处理一个大小为98的数组`a`,其元素是从1到100的一百个...
计算一维数组中所有元素之和的基本算法非常简单:初始化一个变量(初始值通常为零),然后遍历数组中的每一个元素,将当前元素的值加到变量上。当遍历完整个数组后,变量的值即为所有元素的总和。 三、LV中的数组...
sample函数的第一个参数是一个序列,表示要从中选取随机元素的范围;第二个参数是一个整数,表示要选取的随机元素个数。同时,我们还需要根据实际情况修改代码中的数组范围和选取的随机元素个数。
对于数组排列组合问题,我们可以设计一个递归函数,从每个数组的第一个元素开始,依次尝试将每个元素放入结果数组,并递归处理剩余的元素和数组。 以下是一个简单的Java实现思路: 1. 定义一个递归函数,接收当前...
用C#定义多个数组,把多个数组中的元素集合到一个数组中并输出,源代码、简单易懂
从数组中随机获取一个元素,可以使用`Math.random()`函数结合数组索引来实现。`Math.random()`返回一个介于0(包括)到1(不包括)之间的随机数。例如,我们可以这样做: ```javascript let randomIndex = Math....
这个问题可以通过一个名为`sortArr`的函数来解决,它接收两个参数:一个数组(`arr`)和一个字符串(`str`),然后返回一个新的数组,其中的元素是原数组中具有相同属性值的对象的集合。 首先,让我们详细解析`...
将一个随机数组中的相同元素分类放入不同数组中。目前处于输出阶段。
在C#编程中,创建一个包含10个元素的一维整型(int)数组并在声明时直接赋值是一项基本操作。接下来我们将深入探讨如何实现这一任务,以及如何使用循环语句和随机数生成来选取数组中的5个不重复的元素。 首先,让我们...
核心逻辑可以封装在一个递归方法中,每次递归选择一个数组中的元素,然后对剩余的数组继续进行相同的操作。以下是基本的步骤: 1. **初始化**:定义一个空的结果列表,用于存储所有组合。 2. **递归函数**:设计一...
然而,在实际的合并操作中可能会遇到一个问题:当一个数组的元素全部被合并完毕之后,另一个数组可能还会有剩余的元素未被处理。对于这种情况,我们可以直接将剩余数组中未被合并的元素追加到数组c的末尾。由于我们...
该算法的基本思想是从最后一个元素开始,遍历到第一个元素,每次随机选取一个未处理的元素与当前位置的元素交换。以下是易语言实现Fisher-Yates算法的步骤: 1. 定义一个函数,例如“随机打乱数组”,接收一个数组...
【输入形式】用户在第一行输入第一个有序数组的元素数目,以回车结束此输入。然后在第二行按照刚才输入的元素数目依次输入数组元素,中间用空格分隔,最后用回车结束输入。第三行和第四行只需重复刚才的步骤,将第二...
这个实现起来虽然不难,但是涉及到PHP中几个不常用的函数模块,对于很多PHP新手来说还确实是一个难题,今天就给大家分享一个实例,用4行代码就可以实现让PHP随机从数组中选取几个值,然后拼接成字符串并输出。...
在LabVIEW编程环境中,删除一维数组中的所有0元素是一个常见的操作,特别是在处理数据过滤、数据分析或信号处理等任务时。下面将详细讲解如何在LabVIEW中实现这一功能。 首先,我们需要理解LabVIEW的基本概念。...
可以先创建一个`Random`对象,然后用它来填充数组: ```csharp Random rand = new Random(); for (int i = 0; i ; i++) { numbers[i] = rand.Next(1, 100); // 生成1到100之间的随机整数 } ``` 对于数组的统计...
我们可以创建一个优先队列,其中每个元素都是一个带有随机权重的数组索引。每次从队列中取出最小权重的元素(即随机生成的权重),并将其权重置为最大值,这样可以保证每个元素只被取出一次。代码如下: ```java ...
本文将深入探讨如何实现这个功能,以标题“从数组中删除一个元素”为例,通过提供的代码片段进行解析。 首先,我们看到代码中定义了一个整型数组`a`,大小为10,用`for`循环初始化了数组元素。初始化表达式`i*3+2`...
当需要插入元素时,可以创建一个新的、更大的数组,然后将原数组元素复制过来,最后在新位置插入元素。这种方法的缺点是需要额外的内存管理和可能导致内存泄漏。 2. 使用容器类:C++标准库提供了容器类,如`std::...