题目:
题目很长,耐心看完。
给定一个整型数组int[] arr,一个布尔数组boolean[] op,两个数组一定等长,假设长度为N,arr[i]代表客户ID,op[i]表示客户操作 。
arr[3,1,1,4,6]
op [T,T,F,F,T]
代表的意思为,3号客户买了一件商品,1号客户买了1件商品,1号客户退的一件商品,4号客户退了一件商品,6号客户买了一件商品。
每个arr[i]和op[i]都代表着客户的一个事件:T为购买商品,F为退货。
现在,你作为负责人,要在每个事件来时,都给购买次数最多的前K名用户颁奖,所以每个事件发生后,都需要一个获奖名单(得奖区)
得奖规则
public static class Customer {
private int id;
private int buyNum;
private int enterTime;
public Customer(int id, int buyNum, int enterTime) {
this.id = id;
this.buyNum = buyNum;
this.enterTime = enterTime;
};
}
public static class DeJiangQuComparator implements Comparator<Customer> {
@Override
public int compare(Customer o1, Customer o2) {
return o1.buyNum != o2.buyNum ? (o1.buyNum - o2.buyNum) : o1.enterTime - o2.enterTime;
}
}
public static class HouXuanQuComparator implements Comparator<Customer> {
@Override
public int compare(Customer o1, Customer o2) {
return o2.buyNum != o1.buyNum ? o2.buyNum - o2.buyNum : o2.enterTime - o1.enterTime;
}
}
public static List<List<Integer>> compare(int[] arr, boolean[] op, int k) {
//每一步产生一个获奖名单,获奖名单中会有多个人,所以是个List
List<List<Integer>> ans = new ArrayList<>();
//key:用户id value:具体的用户实例
Map<Integer, Customer> map = new HashMap<>();
List<Customer> deJiangQu = new ArrayList<>();
List<Customer> houXuanQu = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
boolean buyOrRefund = op[i];
int id = arr[i];
//如果当前是一个退货操作,并且map中不包含该用户
//可以理解成脏数据的情况
if (!buyOrRefund && !map.containsKey(id)) {
ans.add(getCurAns(deJiangQu));
continue;
}
//商品数量 = 0,客户第一次购买
if (!map.containsKey(id)) {
map.put(id, new Customer(id, 0, 0));
}
//获取到当前的Customer
Customer c = map.get(id);
//根据用户行为 buyNum++ 或 buyNum--
if (buyOrRefund) {
c.buyNum++;
} else {
c.buyNum--;
}
//如果操作后,buyNum = 0,则移除
if (c.buyNum == 0) {
map.remove(id);
}
//如果两个区域都为null, 说明客户可能是第一次进来
if (!deJiangQu.contains(c) && !houXuanQu.contains(c)) {
//如果得奖区 当前没满,则直接放入得奖区
if (deJiangQu.size() < k) {
c.enterTime = i;
deJiangQu.add(c);
} else {
//否则先放入候选区
c.enterTime = i;
houXuanQu.add(c);
}
}
//清除掉两个区域中,为0的元素
clearZeroBuy(deJiangQu);
clearZeroBuy(houXuanQu);
//得奖区和候选区进行排序。
houXuanQu.sort(new HouXuanQuComparator());
deJiangQu.sort(new DeJiangQuComparator());
//得奖区和候选区可能出现交换行为
move(deJiangQu, houXuanQu, k, i);
ans.add(getCurAns(deJiangQu));
}
return ans;
}
private static void move(List<Customer> deJiangQu, List<Customer> houXuanQu, int k, int time) {
//如果候选区此时为null,则不需要进行交换
if (houXuanQu.isEmpty()){
return;
}
//走到这说明候选区一定有元素
//但是一定会只有一个值,(比如说K = 3 ,需要3个获奖名单a,b,c,而此时c用户进行了退款,buyNum = 0,进行了删除,那么候选区就应该补进来 )
if (deJiangQu.size() < k){
//取候选区中第1个元素
Customer c = houXuanQu.get(0);
//重新设置enterTime
c.enterTime = time;
deJiangQu.add(c);
houXuanQu.remove(0);
}else{
//否则,如果得奖区满了,就必须符合下面的条件
if (houXuanQu.get(0).buyNum > deJiangQu.get(0).buyNum){
//将两个区域元素进行替换,并删除原有位置
Customer oldC = deJiangQu.get(0);
Customer newC = houXuanQu.get(0);
oldC.enterTime = time;
newC.enterTime = time;
deJiangQu.add(newC);
houXuanQu.add(oldC);
deJiangQu.remove(0);
houXuanQu.remove(0);
}
}
}
private static void clearZeroBuy(List<Customer> arr) {
List<Customer> noZero = new ArrayList<Customer>();
for (Customer c : arr) {
if (c.buyNum != 0) {
noZero.add(c);
}
}
arr.clear();
for (Customer c : noZero) {
arr.add(c);
}
}
private static List<Integer> getCurAns(List<Customer> deJiangQu) {
List<Integer> ans = new ArrayList<>();
for (Integer num : ans) {
ans.add(num);
}
return ans;
}
public static class LotteryInfo {
private Map<Integer, Customer> customers;
private HeapGreater<Customer> hxHeap;
private HeapGreater<Customer> djHeap;
private int limit;
public LotteryInfo(int k) {
customers = new HashMap<>();
hxHeap = new HeapGreater<>(new HouXuanQuComparator());
djHeap = new HeapGreater<>(new DeJiangQuComparator());
this.limit = k;
}
public List<List<Integer>> topK(int[] arr, int[] op, int k) {
List<List<Integer>> ans = new ArrayList<>();
LotteryInfo lotteryInfo = new LotteryInfo(k);
for (int i = 0; i < arr.length; i++) {
ans.add(lotteryInfo.getCurAns());
}
return null;
}
private List<Integer> getCurAns() {
List<Customer> customers = djHeap.getAllElements();
List<Integer> ans = new ArrayList<>();
for (Customer c : customers) {
ans.add(c.id);
}
return ans;
}
public void operate(int time, int id, boolean buyOrRefund) {
if (!buyOrRefund && !customers.containsKey(id)) {
return;
}
if (!customers.containsKey(id)) {
customers.put(id, new Customer(id, 0, 0));
}
Customer customer = customers.get(id);
if (buyOrRefund) {
customer.buyNum++;
} else {
customer.buyNum--;
}
if (customer.buyNum == 0) {
customers.remove(id);
}
if (!djHeap.contains(customer) && !hxHeap.contains(customer)) {
if (djHeap.getSize() < limit) {
customer.enterTime = time;
djHeap.add(customer);
} else {
customer.enterTime = time;
hxHeap.add(customer);
}
} else if (hxHeap.contains(customer)) {
if (customer.buyNum == 0) {
hxHeap.remove(customer);
} else {
hxHeap.resign(customer);
}
} else {
if (djHeap.contains(customer)) {
if (customer.buyNum == 0) {
djHeap.remove(customer);
} else {
djHeap.resign(customer);
}
}
}
}
public void heapMove(int time) {
if (hxHeap.isEmpty()) {
return;
}
if (djHeap.getSize() < limit) {
Customer pop = hxHeap.pop();
pop.enterTime = time;
djHeap.add(pop);
} else {
if (hxHeap.peek().buyNum > djHeap.peek().buyNum) {
Customer oldC = djHeap.pop();
Customer newC = hxHeap.pop();
oldC.enterTime = time;
newC.enterTime = time;
djHeap.add(newC);
hxHeap.add(oldC);
}
}
}
}