用户积分抽奖


题目:我们做了一个活动,根据用户的积分来抽奖,用户的积分都保存在一个数组里面
arr = [20, 34, 160, 2…],数组下标就是用户的 ID,则这里:
ID 为 0 的用户的积分是 arr[0] 等于 20 分。
ID 为 1 的用户的积分是 arr[1] 等于 34 分。
请你设计一个抽奖算法,随机抽出一位中奖用户,要求积分越高中奖概率越高。
返回值是中奖用户的 ID
PS: 1<= arr.length <= 50000 且 1<= arr[i] <= 50000
代码写出算法,
并分析其时间复杂度,
为其编写尽量多 unit test。

import java.util.Random;
import java.util.Scanner;
/*思路变化
关于权重首先想到霍夫曼树,构造哈夫曼树算法比较复杂,但是我们通过生成霍夫曼编码匹配前缀应该算法应该比较公平吧,毕竟只有0和1;现的话,30分钟肯定不够。
用户次数问题,根据位数或者份额给次数,但是次数肯定是近似值,不够公平;
奖品的占比修改,这个要判断用户积分改变奖池的概率,实现比较麻烦,而且只能说相对公平;
邻接表,最后的思路
*/
//用时说明,算法实现费时30分钟,主要是想法比较长,还有对算法说明的部分,总耗时间一个小时。
//参考链接: https://blog.youkuaiyun.com/weixin_44484674/article/details/121540132

//PS: 1<= arr.length <= 50000 且 1<= arr[i] <= 50000
/*此算法思想:
把总积分当成一个从0到积分和的线段,各id下的积分代表第id+1段的长度,随机数落点在哪段就是所在id中奖
    一开始想的是邻接表数据结构+随机数类实现目标;
    邻接表是数组加链表的方式,链表存储的是所占起点和终点;
    后面发现转换一下数组表示就好,即每个id下存终点,且此终点是下一个id的起点,统一遵循左闭右开吧。
    实现如下:*/
public class Come {
    //设数组的长度为n
    public static void main(String[] args) {
        Random rd=new Random();
        
        //手动输入用户的积分        
//         Scanner sc=new Scanner(System.in); 
//         int n=sc.nextInt(); 
//         int[] arr=new int[n];
//         for (int i = 0; i < n; i++) { arr[i] = sc.nextInt(); }
//         int[] arr1=switchArr(arr);
        //有初始值的测试 
        
         int[] arr=new int[]{20,34,160,25}; 
         int[] arr1=switchArr(arr); //时间复杂度O(n)
         
         
//         打印出来观察结果
         for (int i = 0;i < arr1.length; i++) { System.out.print(arr1[i]); }
         
         
        
         int max=arr1[arr1.length-1]+1;
         int rand=rd.nextInt(max);//把总份数当成一条线段,随机数落点是等概率的
//         观察生成的随机数,多运行几次就是测试几次
         System.out.println(rand);
         
         //返回id,寻找id     
         int id=findId(rand,arr1);//时间复杂度O(n)
//         打印中奖用户id
         System.out.println(id);
    }

   

    //生成n个随机数代表用户的份额
    public static int[] switchArr(int[] arr) {
        int[] arr1=new int[arr.length];
        for (int i = 0; i <arr.length; i++) {
            for (int j = 0; j <=i; j++) {
                arr1[i]+=arr[j];
            }
        }
        return arr1;
    }
    //返回id
    public static int findId(int rand,int[] arr1) {
        int id=0;
        for (int i = 0; i < arr1.length; i++) {
            if(rand>=arr1[i]&&rand<arr1[i+1]) {
                id=i+1;
                break;//找到了id退出循环
            }
        }
        return id;
    }
    
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值