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;
}
}
分享到:
相关推荐
标题 "现有1~100共一百个自然数,已随机放入一个有98个元素的数组a[98]" 暗示了一个编程问题,其中涉及到数组、随机数和计数算法。在这个问题中,我们需要处理一个大小为98的数组`a`,其元素是从1到100的一百个...
计算一维数组中所有元素之和的基本算法非常简单:初始化一个变量(初始值通常为零),然后遍历数组中的每一个元素,将当前元素的值加到变量上。当遍历完整个数组后,变量的值即为所有元素的总和。 三、LV中的数组...
对于数组排列组合问题,我们可以设计一个递归函数,从每个数组的第一个元素开始,依次尝试将每个元素放入结果数组,并递归处理剩余的元素和数组。 以下是一个简单的Java实现思路: 1. 定义一个递归函数,接收当前...
用C#定义多个数组,把多个数组中的元素集合到一个数组中并输出,源代码、简单易懂
代码如下:[removed] <!– var test = [“aa”,”bb”,”cc”,”dd”,”ee”]; [removed](test[Math.floor(Math.random()*test.length...注意:[ ] 符号在javascript中定义一个数组,{ } 则定义一个对象 随机取得数组
从数组中随机获取一个元素,可以使用`Math.random()`函数结合数组索引来实现。`Math.random()`返回一个介于0(包括)到1(不包括)之间的随机数。例如,我们可以这样做: ```javascript let randomIndex = Math....
这个问题可以通过一个名为`sortArr`的函数来解决,它接收两个参数:一个数组(`arr`)和一个字符串(`str`),然后返回一个新的数组,其中的元素是原数组中具有相同属性值的对象的集合。 首先,让我们详细解析`...
将一个随机数组中的相同元素分类放入不同数组中。目前处于输出阶段。
在C#编程中,创建一个包含10个元素的一维整型(int)数组并在声明时直接赋值是一项基本操作。接下来我们将深入探讨如何实现这一任务,以及如何使用循环语句和随机数生成来选取数组中的5个不重复的元素。 首先,让我们...
核心逻辑可以封装在一个递归方法中,每次递归选择一个数组中的元素,然后对剩余的数组继续进行相同的操作。以下是基本的步骤: 1. **初始化**:定义一个空的结果列表,用于存储所有组合。 2. **递归函数**:设计一...
该算法的基本思想是从最后一个元素开始,遍历到第一个元素,每次随机选取一个未处理的元素与当前位置的元素交换。以下是易语言实现Fisher-Yates算法的步骤: 1. 定义一个函数,例如“随机打乱数组”,接收一个数组...
当其中一个数组(这里假设是数组a)的所有元素都被放入c后,剩下的元素(来自数组b)会被直接追加到c的末尾,因为此时b数组中的元素都比a数组的剩余元素大。同样地,如果数组b先排完,那么数组a的剩余元素会追加到c...
【输入形式】用户在第一行输入第一个有序数组的元素数目,以回车结束此输入。然后在第二行按照刚才输入的元素数目依次输入数组元素,中间用空格分隔,最后用回车结束输入。第三行和第四行只需重复刚才的步骤,将第二...
可以先创建一个`Random`对象,然后用它来填充数组: ```csharp Random rand = new Random(); for (int i = 0; i ; i++) { numbers[i] = rand.Next(1, 100); // 生成1到100之间的随机整数 } ``` 对于数组的统计...
我们可以创建一个优先队列,其中每个元素都是一个带有随机权重的数组索引。每次从队列中取出最小权重的元素(即随机生成的权重),并将其权重置为最大值,这样可以保证每个元素只被取出一次。代码如下: ```java ...
在LabVIEW编程环境中,删除一维数组中的所有0元素是一个常见的操作,特别是在处理数据过滤、数据分析或信号处理等任务时。下面将详细讲解如何在LabVIEW中实现这一功能。 首先,我们需要理解LabVIEW的基本概念。...
本文将深入探讨如何实现这个功能,以标题“从数组中删除一个元素”为例,通过提供的代码片段进行解析。 首先,我们看到代码中定义了一个整型数组`a`,大小为10,用`for`循环初始化了数组元素。初始化表达式`i*3+2`...
当需要插入元素时,可以创建一个新的、更大的数组,然后将原数组元素复制过来,最后在新位置插入元素。这种方法的缺点是需要额外的内存管理和可能导致内存泄漏。 2. 使用容器类:C++标准库提供了容器类,如`std::...
这个过程需要特别注意的是,每次从数组a中删除一个元素后,其后面的元素会向前移动,因此下次遍历时的索引应该相应地减一。 具体到代码实现,我们定义了一个名为`arrChange`的函数,接受两个参数,分别是待处理的...
本问题要求我们创建一个动态数组,其长度由用户输入决定,然后从屏幕上接收一组数字填充数组。接着,我们需要实现一系列功能,包括找到数组中的最大值、最小值以及它们对应的索引。下面将详细介绍如何实现这个任务。...