用户喜好(今日头条算法题)

为了不断优化推荐效果,今日头条每天要存储和处理海量数据。假设有这样一种场景:我们对用户按照它们的注册时间先后来标号,对于一类文章,每个用户都有不同的喜好值,我们会想知道某一段时间内注册的用户(标号相连的一批用户)中,有多少用户对这类文章喜好值为k。因为一些特殊的原因,不会出现一个查询的用户区间完全覆盖另一个查询的用户区间(不存在L1<=L2<=R2<=R1)。

输入描述:
输入: 第1行为n代表用户的个数 第2行为n个整数,第i个代表用户标号为i的用户对某类文章的喜好度 第3行为一个正整数q代表查询的组数 第4行到第(3+q)行,每行包含3个整数l,r,k代表一组查询,即标号为l<=i<=r的用户中对这类文章喜好值为k的用户的个数。 数据范围n <= 300000,q<=300000 k是整型

输出描述:
输出:一共q行,每行一个整数代表喜好值为k的用户的个数

输入例子1:
5
1 2 3 3 5
3
1 2 1
2 4 5
3 5 3

输出例子1:
1
0
2

例子说明1:
样例解释:
有5个用户,喜好值为分别为1、2、3、3、5,
第一组询问对于标号[1,2]的用户喜好值为1的用户的个数是1
第二组询问对于标号[2,4]的用户喜好值为5的用户的个数是0
第三组询问对于标号[3,5]的用户喜好值为3的用户的个数是2
解题方式1:时间复杂度O(n^2)

	import java.util.*;
	public class Main {
	public static void main(String []args) {
		
		Scanner sc = new Scanner(System.in);
		int count = Integer.parseInt(sc.nextLine());//人数
		
		//用户喜好度数组
		int [] fav = new int[count+1];//牺牲掉空间0,从1开始计数
		String[] str = sc.nextLine().split("\\s+");
		for(int i = 1; i < count+1; i++) {
			fav[i] = Integer.parseInt(str[i-1]);
		}
		
		int groups = Integer.parseInt(sc.nextLine());//组数
		
		for(int i = 0; i < groups; i++) {
			String[] g = sc.nextLine().split("\\s+");
			int l = Integer.parseInt(g[0]);
			int r = Integer.parseInt(g[1]);
			int k = Integer.parseInt(g[2]);
			
			int c = 0; //记录喜好数
			for(int j = l; j <= r; j++) {
				if(fav[j] == k)
					c++;
			}
			
			System.out.println(c);
			
		}
		

		sc.close();

	}
}

这种解法,在牛客网上跑由于时间复杂度问题,也仅能通过50%的测试用例

解法2:HashMap

		import java.util.*;
			public class Main {
				public static void main(String []args) {
				
				Scanner sc = new Scanner(System.in);
				int count = Integer.parseInt(sc.nextLine());//人数
				
				HashMap<Integer, List<Integer>> hs = new HashMap<>();
		
				
				String[] str = sc.nextLine().split("\\s+");
				for(int i = 1; i < count+1; i++) {//从1开始计数
					int k = Integer.parseInt(str[i-1]);
					if (hs.get(k) != null) {
						hs.get(k).add(i);
						hs.get(k).set(0, hs.get(k).size()-1);
					}else {
						List<Integer> ls = new ArrayList<>(2);
						ls.add(1);
						ls.add(i);
						hs.put(k, ls);
					}
					
		
				}
				
				
				int groups = Integer.parseInt(sc.nextLine());//组数
				
				for(int i = 0; i < groups; i++) {
					String[] g = sc.nextLine().split("\\s+");
					int l = Integer.parseInt(g[0]);
					int r = Integer.parseInt(g[1]);
					int k = Integer.parseInt(g[2]);
					
					if (hs.get(k) == null) {
						System.out.println(0);
						continue;
					}
					
					int len = hs.get(k).size();
					if (hs.get(k).get(len-1) < l) {
						System.out.println(0);
						continue;
					}
					
					int c = 0;
					for(int t = 1; t <= hs.get(k).get(0); t++) {
						if(hs.get(k).get(t) >= l && hs.get(k).get(t) <= r){
		                    c++;
		                    continue;
		                }
		                if (r < hs.get(k).get(t)){
		                    break;
		                }
					
					}
					System.out.println(c);
				}
		
				sc.close();
		
				
			
			}
		}

解法3:二分法+快排求解
(解法三可能有点问题等以后有空再做修改)

package test;
		
import java.util.Scanner;
		
public class UserFav {
		public static class User{
			int code;//用户标号
			int k;//用户喜好
			@Override
			public String toString() {
					return "User [code=" + code + ", k=" + k + "]";
				}
	
	
}

public static void main(String []args) {
	Scanner sc = new Scanner(System.in);
	int count = Integer.parseInt(sc.nextLine());//用户量
	User[] us = new User[count];
	String[] ks = sc.nextLine().split("\\s+");
	for (int i=0; i<ks.length; i++) {
		User u = new User();
		u.code = i;
		u.k = Integer.parseInt(ks[i]);
		us[i] = u;
	}
	
	quickSort(us, 0, us.length-1);
	
	int gs = Integer.parseInt(sc.nextLine());
	if (gs == 0) return;
	

	for (int i=0; i<gs; i++) {
		String[] inf = sc.nextLine().split("\\s+");
		int lt = Integer.parseInt(inf[0])-1;
		lt = lt > -1 ? lt : 0;
		int rt = Integer.parseInt(inf[1])-1;
		rt = rt > -1 ? rt : 0;
		rt = rt <= us.length-1 ? rt : us.length-1;
		int k = Integer.parseInt(inf[2]);
		int p = binarySearch(us, 0, us.length-1, k);	
		
		int q = p+1;
		int c = 0;
		while (p >= 0) {
			if(us[p].k != k)
				break;
			if (us[p].code <= rt && us[p].code >= lt) 
				c++;
			p--;
		}
		
		while (q <= us.length-1) {
			if (us[q].k != k)
				break;
			
			if (us[q].code <= rt && us[q].code >= lt) 
				c++;
			
			q++;
			
		}
		System.out.println(c);
	}
	
	sc.close();
}

//快排(按喜好排序)
public static void quickSort(User[] arr, int l, int h) {
	if (l == h) return;//递归出口
	
	User tmp = arr[l];//取出低位数,作为本轮排序目标数
	int low = l;
	int high = h;
	//开始寻找目标数位置
	while(low < high) {
		while (tmp.k < arr[high].k) {//从右往左
			high--;
		}
		if (low < high) {
			arr[low] = arr[high];
			arr[high] = tmp;
			low++;
		}
		
		while (tmp.k > arr[low].k) {
			low++;
		}
		if (low < high) {
			arr[high] = arr[low];
			arr[low] = tmp;
			high--;
		}
	}
	
	if (l < low-1) 
		quickSort(arr, l, low-1);
	
	
	if (high+1 < h)
		quickSort(arr, high+1, h);
	
}

//param: arr,有序数组	l,左边界		r,右边界		k,查找值
public static int binarySearch(User[] arr, int l, int r, int k) {

	int mid = (l+r)/2;//折半中间点
	
	if (arr[mid].k == k) {
		return mid;//成功查找,递归出口
	}
	
	if (l == r) {
		return -1;//查找失败,递归出口
	}
	
	if (arr[mid].k > k) {//查找方向
		return binarySearch(arr, l, mid-1, k);//不可能出现mid == r 或mid == l情况
	}
	return binarySearch(arr, mid+1, r, k);
}

}

猜你喜欢

转载自blog.csdn.net/weixin_43247186/article/details/86710779