论坛首页 Java企业应用论坛

一道阿里电话面试中的算法题

浏览 46250 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (3) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-10-09  
qvjing520 写道
我测了一下感觉效率换可以,希望大家指教
public class Num2 {
//找出一个数组中重复元素最多的元素并打印出来
    private static int[] num1 = {1, 2, 2 ,3,4,4,4,5,6,6,6,6,7,10,11,11,11,11,11,11,15};
    private static Object[] num =null;
    Map<Integer,Integer> map = new HashMap<Integer,Integer>();
   
    static
    {
    List lst = new ArrayList();
    for(int i=0;i<10000;i++)
    {
    for(Integer temp:num1)
    {
    lst.add(temp);
    }
    }
    num = lst.toArray();
    }
   
    public static void main(String[] args) {
//System.out.println("second");
    new Num2().find(num);
}
   
  
   
    private void find(Object[] data)
    {
    long time = System.currentTimeMillis()/1000;
    for(int i=0;i<data.length;i++)
    {
    if(map.containsKey(data[i]))
    {
    int t=map.get(data[i]);
    map.put((Integer)data[i], ++t);
    }
    else
    {
    map.put((Integer)data[i], 1);
    }
   
    }
        int max = java.util.Collections.max(map.values());
       
    for(Integer key:map.keySet())
    {
    if(map.get(key)==max)
    {
    System.out.println("number:"+key+" value:"+max);
    }
    }
    System.out.println(time-(System.currentTimeMillis()/1000));
   
    }
   
}


这么点数据能说明什么问题啊,起码几十万个数才行啊
0 请登录后投票
   发表时间:2010-10-09  
 public static void findRepeatMaxValue(int[] arr) {
		long time1 = System.nanoTime();
		HashMap<Integer, Integer> box = new HashMap<Integer, Integer>();
		int maxValue = 0;
		int maxCount = 0;
		for (int i = 0; i < arr.length; i++) {
			Integer count = box.get(arr[i]);
			box.put(arr[i], count == null ? 1 : ++count);
			int newCount = box.get(arr[i]);
			if(newCount > maxCount) {
				maxCount = newCount;
				maxValue = arr[i];
			}
		}
		long time2 = System.nanoTime();
		System.out.println("findRepeatMaxValue time is "
				+ ((time2 - time1) / 1000000.0) + "ms");
		System.out.println("maxValue : " + maxValue +"  maxCount : " + maxCount);
	}

 public static void main(String[] args) {
		Random rand = new Random();	
		int arr[] = new int[1000000];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = rand.nextInt(100);
		}
		findRepeatMaxValue(arr);
	}


测试结果:
测试数量:1000000
findRepeatMaxValue time is 146.057722ms
maxValue : 50  maxCount : 10261


0 请登录后投票
   发表时间:2010-10-09   最后修改:2010-10-09
lewisw 写道
qvjing520 写道
我测了一下感觉效率换可以,希望大家指教
public class Num2 {
//找出一个数组中重复元素最多的元素并打印出来
    private static int[] num1 = {1, 2, 2 ,3,4,4,4,5,6,6,6,6,7,10,11,11,11,11,11,11,15};
    private static Object[] num =null;
    Map<Integer,Integer> map = new HashMap<Integer,Integer>();
   
    static
    {
    List lst = new ArrayList();
    for(int i=0;i<10000;i++)
    {
    for(Integer temp:num1)
    {
    lst.add(temp);
    }
    }
    num = lst.toArray();
    }
   
    public static void main(String[] args) {
//System.out.println("second");
    new Num2().find(num);
}
   
  
   
    private void find(Object[] data)
    {
    long time = System.currentTimeMillis()/1000;
    for(int i=0;i<data.length;i++)
    {
    if(map.containsKey(data[i]))
    {
    int t=map.get(data[i]);
    map.put((Integer)data[i], ++t);
    }
    else
    {
    map.put((Integer)data[i], 1);
    }
   
    }
        int max = java.util.Collections.max(map.values());
       
    for(Integer key:map.keySet())
    {
    if(map.get(key)==max)
    {
    System.out.println("number:"+key+" value:"+max);
    }
    }
    System.out.println(time-(System.currentTimeMillis()/1000));
   
    }
   
}


这么点数据能说明什么问题啊,起码几十万个数才行啊


测试了一下,900000*21=18900000的数据(约一千九百万),再多就报错了,应该是内存的问题,这个不关心了。

MAX_number:11     MAX_value:5400000

cost:1062ms

qvjing520 的速度比楼上稍好
0 请登录后投票
   发表时间:2010-10-09  
clufeng 写道
 public static void findRepeatMaxValue(int[] arr) {
		long time1 = System.nanoTime();
		HashMap<Integer, Integer> box = new HashMap<Integer, Integer>();
		int maxValue = 0;
		int maxCount = 0;
		for (int i = 0; i < arr.length; i++) {
			Integer count = box.get(arr[i]);
			box.put(arr[i], count == null ? 1 : ++count);
			int newCount = box.get(arr[i]);
			if(newCount > maxCount) {
				maxCount = newCount;
				maxValue = arr[i];
			}
		}
		long time2 = System.nanoTime();
		System.out.println("findRepeatMaxValue time is "
				+ ((time2 - time1) / 1000000.0) + "ms");
		System.out.println("maxValue : " + maxValue +"  maxCount : " + maxCount);
	}

 public static void main(String[] args) {
		Random rand = new Random();	
		int arr[] = new int[1000000];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = rand.nextInt(100);
		}
		findRepeatMaxValue(arr);
	}


测试结果:
测试数量:1000000
findRepeatMaxValue time is 146.057722ms
maxValue : 50  maxCount : 10261





楼主说是数组中重复次数最多的元素,而且我认为出现最多次数也有可能不同元素出现相同次数且是最多的,而上面的只显示最大了。
0 请登录后投票
   发表时间:2010-10-09  

    public static void findRepeatMaxValue(int[] arr) {

       long time1 = System.nanoTime();

       int max = 0;

       // 定义MAP KEY表示存放的数字,VALUES表示出现的次数

       Map<Integer, Integer> map = new HashMap<Integer, Integer>();

       for (int n : arr) {

           if (map.containsKey(n)) {

              map.put(n, map.get(n) + 1);

           } else {

              map.put(n, 1);

           }

           // 比较是此数是否为最大次数

           if (map.get(n) > max)

              max = map.get(n);

       }

 

       for (Map.Entry<Integer, Integer> m : map.entrySet()) {

           if (m.getValue() == max) {

              System.out.println(m.getKey() + " 出现了 " + m.getValue() + " .");

           }

 

       }

 

       long time2 = System.nanoTime();

       System.out.println("findRepeatMaxValue time is "

              + ((time2 - time1) / 1000000.0) + "ms");

 

    }

 

    public static void main(String[] args) {

       Random rand = new Random();

       int arr[] = new int[1000000];

       for (int i = 0; i < arr.length; i++) {

           arr[i] = rand.nextInt(100);

       }

       findRepeatMaxValue(arr);

0 请登录后投票
   发表时间:2010-10-09  
Crusader 写道
hikaru1012 写道
sunhj000java 写道
我认为这道题的关键是如何遍历这个数据集合,如果能不用遍历集合而找出出现最多的次数的数字是这道题的关键。
我们可以用hashmap保存数据出现的个数,并且用两个变量保存出现最多的次数(max1)和次多的次数(max2),当剩下的数据个数小于max1-max2,那么我们就找出了这个数字了。
最优为n/2  最差为n


如何维护记录出现次数最多和次多的变量要比实现问题本身困难得多吧?


+1
无论在时间和空间上都会耗费很多额外的消耗来维护“最多”与“次多”,我认为大多数情况可能都会得不偿失。。

这个应该不会消耗太多资源吧,在开始比较的时候就确定最多和次多两个变量,在每次改动对应数字的次数时和次多比较一下就可以了,如果大于次多就替换次多并和最多比较,如果也大于最多也替换,否则不做任何操作。这个动作并不消耗太多资源吧
0 请登录后投票
   发表时间:2010-10-10   最后修改:2010-10-10
《编程珠玑》第二章有讲到相关内容
在线性时间排序算法(Linear-Time Sorting)中到计数排序(Counting Sorting)或许是解决这个问题的。具体java实现:

public class CountingSort {
	private static final int N= 10000;
	private static final int K= 1000;
	/**
	 * 得到计数数组
	 * @param num
	 * @return
	 */
	public static int[] computeCountingNum(int[] num){
		int maxAppearNum = 0;
		int count = 0;
		int[] countingNum = new int[K];
		int value,countTmpValue;
		for(int i=0;i<N;i++){
			value = num[i];
			countTmpValue = countingNum[value];
			//查找出现次数最多的数字
			if(countTmpValue > count){
				count = countTmpValue;
				maxAppearNum = value;
			}                 
			countingNum[value] = countingNum[value] + 1; 
		}
		//打印出满足阿里面试要求到数据
		System.out.println("\n"+maxAppearNum);
		System.out.println(count);
		return countingNum;
	}
	/**
	 * 遍历计数数组,得到排序结果
	 * @param num
	 * @return
	 */
	public static int[] sortedNum(int[] num){
		int[] countingNum = computeCountingNum(num);
		int[] sortedNum = new int[N];
		int value;
		int j = 0;
		for(int i=0;i<K;i++){
			value = countingNum[i];
			if(value > 0){
				while(value > 0){
					sortedNum[j] = i;
					--value;
					++j;
				}
			}
		}
		return sortedNum;
	}
	/**
	 * 产生随机数
	 * @return
	 */
	public static int[] randomNumber(){
		int[] num = new int[N];
		Random random = new Random();
		for(int i=0;i<N;i++){
			int m = random.nextInt(K);
			num[i] = m;
		}
		return num;
	}
	
	public static void main(String[] args) {
		int[] num = CountingSort.randomNumber();
		//计数排序耗时
		long t1 = System.currentTimeMillis();
		CountingSort.sortedNum(num);
		long t2 = System.currentTimeMillis();
		System.out.print(t2-t1);
		System.out.println();
		//快速排序耗时
		long t3 = System.currentTimeMillis();
		Arrays.sort(num);
		long t4 = System.currentTimeMillis();
		System.out.print(t4-t3);
	}
}

具体讨论的博文:http://www.longtask.com/blog/?p=616
0 请登录后投票
   发表时间:2010-10-13  

看了楼主的代码,想自己试试,结果发现你那第一种方法很明显是有错误的,更正后的代码如下:

 

		ArrayUtil.quickSort(arr, 0, arr.length - 1);
		
		int now = 1;
		int pre = 1;
		for(int i = 0; i < arr.length - 1; i ++) {
			if(arr[i] == arr[i + 1]) {
				now ++;
			} else {
				if(now >= pre) {
					pre = now;
				}
//now = 1;应该放在if语句的外面
				now = 1;
			}
		}
//缺少这一句
		if(now >= pre) {
			pre = now;
		}
 
0 请登录后投票
   发表时间:2010-10-20  
lewisw 写道
leves 写道

 

public static void find3(int[] arr){
		HashMap<Integer,Integer> hm=new HashMap<Integer, Integer>();
		for(int i=0;i<arr.length;i++){
			if(hm.containsKey(arr[i])) {
				int count=hm.get(arr[i]);
				hm.put(arr[i], ++count);
			 
			}else{
				hm.put(arr[i],1);
			}
		}
		
		Iterator<Entry<Integer, Integer>> it=hm.entrySet().iterator();
		int pre=0;
		int max=arr[0];
		while(it.hasNext()) {
			Entry<Integer, Integer> en=it.next();
			int key=en.getKey();
			int val=en.getValue();
			if(val>pre){	
				pre=val;
				max=key;
			}
			
		}
		
		//System.out.println(max);
		
	}

 

用Hash的方式写的,为什么测试的时候速度上反而是最慢的

 

这个map创建的时候一定要考虑他的两个构造参数(int initialCapacity, float loadFactor),非常重要, 尤其数据量大的时候, 不然老是在哪里构造新的大的数组然后拷贝,越大越慢, 最后慢死你。

HashMap的内部使用数组+链表保存数据, 默认的initialCapacity=16, loadFactor = 0.75, 具体的自己参考文档。

 

你可以这样HashMap<Integer,Integer> hm=new HashMap<Integer, Integer>(arr.length);

当然一定要确认这个arr.length是不是太大了,内存溢出,数组的length在java里是int的,就是说最大值是4g, 你的内存大大,虚拟机能分配那么多也行,呵呵

补充一点,初始容量和装载因子是影响hash函数性能的重要因子,也就是影响你地址是否冲突的重要因素,当地址冲突时,选择合适的再散列函数,对相应元素进行地址分配,以便无冲突装载该元素,这个也是很重要的,

0 请登录后投票
   发表时间:2010-10-20  
我也不会解啊, 这么有才的题目。
如果是有限内存, 海量数据的话, 谁能给一个接近O(N)的算法呢。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics