首页 > 试题广场 >

用户喜好

[编程题]用户喜好
  • 热度指数:8609 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

为了不断优化推荐效果,今日头条每天要存储和处理海量数据。假设有这样一种场景:我们对用户按照它们的注册时间先后来标号,对于一类文章,每个用户都有不同的喜好值,我们会想知道某一段时间内注册的用户(标号相连的一批用户)中,有多少用户对这类文章喜好值为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
0
2

说明

样例解释:
有5个用户,喜好值为分别为1、2、3、3、5,
第一组询问对于标号[1,2]的用户喜好值为1的用户的个数是1
第二组询问对于标号[2,4]的用户喜好值为5的用户的个数是0
第三组询问对于标号[3,5]的用户喜好值为3的用户的个数是2
n = int(input())   #这道题用暴搜肯定超时,但是用Python的字典会非常简单

user_array = list(map(int,input().strip().split()))

user_dict = dict()            #创建一个字典
for i in range(len(user_array)):   #对应的键值是用户喜爱程度,value值是一个列表,对应相应的用户id
   if user_dict.__contains__(user_array[i]):
      user_array_list_i = list(user_dict[user_array[i]])
      user_array_list_i.append(i+1)
      user_dict[user_array[i]] = user_array_list_i
   else:
      user_array_list_i = []
      user_array_list_i.append(i+1)
      user_dict[user_array[i]] = user_array_list_i

q = int(input())

for i in range(q):
      query = list(map(int,input().strip().split()))
      start_index = query[0]
      end_index = query[1]
      k = query[2]

      if user_dict.__contains__(k):
          query_list = user_dict[k]    #通过键值找到这个喜爱程度对应所有的用户id

          count = 0

          for j in range(len(query_list)):
             if start_index <= query_list[j] <= end_index:
                 count += 1

          print(count)
      else:
          print(0)
   
编辑于 2019-04-10 11:58:28 回复(1)
import java.util.*;
/*
思路1、直接每个请求过一遍数组,完全暴力,O(n),超时
思路2、
采用含list的map来表示;
然后对key可进行二分查找,在对应key的list里面也可以采用二分找下标;
但是发现这种存储思路,即使是不二分,也不会超时
注意以下几点:
【1】思路
【2】输入的l,r是从1开始,而数组存储是从0开始的,读取输入之后要-1
【3】不需要输入端点刚好等于存储的list的值,只要在[l,r]区间内就可以了
*/

public class Main{
    
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        sc.nextLine();
        int[] sn=new int[n];
        Map<Integer, ArrayList<Integer>> map=new HashMap<Integer, ArrayList<Integer>>();
        for(int i=0;i<n;i++){
            //得到的数组处理一下
            sn[i]=sc.nextInt();
            if(map.containsKey(sn[i])){
                ArrayList<Integer> alist=map.get(sn[i]);
                alist.add(i);
                map.put(sn[i],alist);
            }
            else{
                ArrayList<Integer> alist=new ArrayList<Integer>();
                alist.add(i);
                map.put(sn[i],alist);
            }
        }
        //
        sc.nextLine();
        int q=sc.nextInt();
        for(int i=0;i<q;i++){ //对每个query求取
            sc.nextLine();
            int l=sc.nextInt()-1;
            int r=sc.nextInt()-1;
            int k=sc.nextInt();
            if(!map.containsKey(k)){
                System.out.println(0);
                continue;
            }
            ArrayList<Integer> alist=map.get(k);
            int size=alist.size();
            int ll=0;
            int rr=size-1;
            if((alist.get(rr)<l) || (alist.get(ll)>r)){//区间完全不覆盖,则排除
                System.out.println(0);
                continue;
            }
            else{
                while(alist.get(ll)<l)
                    ll++;
                while(alist.get(rr)>r)
                    rr--;
            }
            System.out.println(rr-ll+1);
        }
    }
    
}
发表于 2019-07-07 14:15:18 回复(3)
<?php
// 已通过所有用例
functiongetArrFromLine($pattern,$split,$num) {
$arr= [];
$p_str= "";
for($i= 0; $i<$num; $i++) {
if($i!= $num-1)
{
$p_str.= "{$pattern}{$split}";
}
else{
$p_str.= "{$pattern}\n";
}
//$arr[$i] = null;
}
$paramters= [STDIN,$p_str];
for($i= 0; $i<$num; $i++) {
$paramters[$i+2] = &$arr[$i];
}
call_user_func_array('fscanf',$paramters);
return$arr;
}
fscanf(STDIN, "%d",$users);
$karr= getArrFromLine("%d"," ",$users);
$kmap= [];
for($i=0;$i<$users;$i++) {
$k= $karr[$i];
if(isset($kmap[$k]) && is_array($kmap[$k])) {
array_push($kmap[$k],$i+1);
}
else{
$kmap[$k] = [$i+1];
}
}
//print_r($kmap);
fscanf(STDIN, "%d",$groups);
$res= [];
for($i=0; $i<$groups; $i++) {
$res[$i] = 0;
list($start_id,$end_id,$k) = getArrFromLine("%d"," ",3);
if(is_array($kmap[$k])) {
foreach($kmap[$k] as$uid) {
if($start_id<=$uid&& $uid<=$end_id)
$res[$i]++;
}
}
}
foreach($resas$r) {
echo$r,"\n";
}
?>

编辑于 2019-03-15 22:37:12 回复(0)
 

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        HashMap<Integer,ArrayList<Integer>> hm=new HashMap<Integer,ArrayList<Integer>>();
        for(int i=0;i<n;i++) {
            int temp=sc.nextInt();
            if(hm.containsKey(temp)) {
                hm.get(temp).add(i);
            }else {
                ArrayList<Integer> al=new ArrayList<Integer>();
                al.add(i);
                hm.put(temp,al);
            }
             
        }
        
        int m=sc.nextInt();
        int b[]=new int[m];
         
        for(int j=0;j<m;j++) {
            int low=sc.nextInt()-1;
            int high=sc.nextInt()-1;
            int key=sc.nextInt();
            if(!hm.containsKey(key)) {
                b[j]=0;
            }else {
                b[j]=getNum(low, high,hm.get(key));
            }
             
        }
        for(int j=0;j<m;j++) {
            System.out.println(b[j]);
        }
         
         
        sc.close();
     

    }
    public static int getNum(int low ,int high,ArrayList<Integer> al) {
        int i=0;
        int j=al.size()-1;
        if(al.get(i)>high || al.get(j)<low ) {
            return 0;
        }else {
            while(al.get(i)<low || al.get(j)>high) {
                if(al.get(i)<low) i++;
                if(al.get(j)>high) j--;
            }
            return j-i+1;
        }
         
        
    }
     

}

发表于 2018-03-23 17:02:40 回复(2)
#include <bits/stdc++.h>
using namespace std;

int main(){
    int n, q, l, r, k;
    scanf("%d", &n);
    int a[n+1];
    map<int, vector<int>> mp;
    for(int i=1;i<=n;i++){
        scanf("%d", &a[i]);
        mp[a[i]].push_back(i);
    }
    scanf("%d", &q);
    for(int i=0;i<q;i++){
        scanf("%d%d%d", &l, &r, &k);
        if(mp.find(k) == mp.end())
            puts("0");
        else{
            auto v = mp[k];
            auto ll = lower_bound(v.begin(), v.end(), l);
            auto rr = upper_bound(v.begin(), v.end(), r);
            printf("%ld\n", rr-ll);
        }
    }
    return 0;
}

发表于 2020-12-12 20:30:34 回复(0)
#include <iostream>
#include <unordered_map>
#include <vector>
#include <algorithm>
using namespace std;

int main() {

	int n;
	cin >> n;
	unordered_map<int,vector<int>> kMapUser;
	for (int i = 0; i < n; i++) {
		int kValue;
		cin >> kValue;
		kMapUser[kValue].push_back(i+1);  //向量中的元素自动有序,这点很好
	}

	int q;
	cin >> q;
	for (int i = 0; i < q; i++) {
		int startUserIndex, endUserIndex, kvalue;
		cin >> startUserIndex >> endUserIndex >> kvalue;
		auto users = kMapUser[kvalue];
		auto low = lower_bound(users.begin(), users.end(), startUserIndex);
		auto high = upper_bound(users.begin(), users.end(), endUserIndex);
		cout << high - low << endl;
	}


	//system("Pause");
	return 0;
}

发表于 2020-06-29 11:51:23 回复(0)
虽然我的方法最终还是超时了,但是可以为大家提供多一条思路:
//线段树区间查询(超时)
int layer, sum, first, last;	//层数,总结点数,子节点下标起点、终点
int ql, qr, qt;	//查询范围的起点终点的真实下标
map<pair<pair<int,int>,int>, int> history;	//历史查询记录
//传入元素个数,初始化满二叉树参数,返回总结点数
int init(int n){
	sum = 1, layer=1;
	int tmp = 1;	//满二叉树页节点的个数
	while (tmp < n){
		tmp *= 2;
		sum += tmp;
		layer++;
	}
	sum = sum - tmp + n;
	first = pow(2, layer - 1) - 1;
	last = first + n -1;	//失误:漏了-1
	return sum;
}
//i:当前节点下标,返回能到达的叶子节点左边界
int getLeft(int i){
	while (i < first){
		i = i * 2 + 1;
	}
	return i;
}
//i:当前节点下标,返回能到达的叶子节点右边界
int getRight(int i){
	while (i < first){
		i = i * 2 + 2;
	}
	return i;
}
//查询函数,i:当前节点所在下标
int Query(int i){
	if (i >= first){	//叶子节点
		if (i >= ql && i <= qr){	//重大失误:没有判断i是否在查询的范围!
			return history[{{i, i},qt}];
		}
		return 0;
	}
	int lr = getLeft(i);
	int rr = getRight(i);
	if (rr < ql || lr > qr){	//与查询边界没有交集
		return 0;
	}
	if (lr >= ql && rr <= qr){	//完全包含在查询边界里
		if (history.find({ { lr, rr } , qt}) != history.end()){//已有记录
			return history[{{lr, rr}, qt}];
		}
		int total = Query(i * 2 + 1) + Query(i * 2 + 2);
		history.insert({ { { lr, rr } ,qt}, total});
		return total;
	}
	return Query(i * 2 + 1) + Query(i * 2 + 2);
}
int main(){
	int n;
	cin >> n;
	init(n);
	//为子节点赋值
	for (int i = 0; i < n; i++){
		int t;
		scanf("%d", &t);
		history.insert({ { { first + i, first + i }, t }, 1 });
	}
	//开始查询
	cin >> n;
	while (n--){
		scanf("%d %d %d", &ql, &qr, &qt);
		ql = ql + first - 1;
		qr = qr + first - 1;
		cout << Query(0) << endl;
	}
	return 0;
}


发表于 2020-03-30 16:17:49 回复(0)
读题挺费劲的,语文没学好。
一开始使用的暴搜,代码很简单,但是通不过啊。猜到,估计测试输入的数据可能会很大。
参考楼上牛客447189284号 的思路写的。用的dict。用dict,提前把用户的数据分好类。直接从分类里面检索,速度会省很多。
再次感谢牛客447189284号
N=int(input())
s=list(map(int,input().split()))
user_dict={}    #建立空的dict
for x in range(N):
    if user_dict.__contains__(s[x]):   #如果包含该key,则直接向value追加数据。value里面是list
        user_dict[s[x]].append(x+1)
    else:
        user_dict[s[x]]=[x+1]       #如果不包含该key,添加。

M=int(input())
for x in range(M):
    [l,r,k]=list(map(int,input().split()))   #边循环,边处理
    result = 0
    if user_dict.__contains__(k):  
        for y in user_dict[k]:
            if l<=y<=r:
                result+=1
    print(result)


编辑于 2020-02-12 16:41:47 回复(0)
#include<iostream> 
#include<vector>
#include<string>
#include<queue>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;

long long n,q;
vector<long> vk;
long long l,r,k;

int main()
{

    //freopen("1.txt","r",stdin);
    cin>>n;
    map<long,vector<long> >my;
    for(long i=1;i<=n;i++)
    {
        long t;
        cin>>t;
        my[t].push_back(i);
    }
    cin>>q;
    for(long i=0;i<q;i++)
    {
     cin>>l>>r>>k;
     if(my.find(k)==my.end())
     {
         cout<<0<<endl;
     }else
     {
         vector<long> vec=my[k];
         long num=0;
         for(int i=0;i<(int)vec.size();i++)
         {
             if(vec[i]>=l&&vec[i]<=r)
             num++;
         }
         cout<<num<<endl;
     }
    
    }
     
    return 0;
}

发表于 2019-03-24 15:52:35 回复(0)
这道题暴力破解好像除了C,其他语言都超时,C++也超时。然后我考虑用动态规划,dp[i][j][k] 表示在i 到 j之间,有多少的k值,然而题目中说k是整型,也就意味着k的取值范围是int的范围,dp数组太大,根本建立不起来。

思来想去,vector和map结合使用,可以相对来说既节省空间有节省时间。
map <int, vector<int> >hobby;
所有出现的喜好值作为键, 值为一个vecotr,其中存储着用户编号。

查找时,先判断map中是否存在这个喜好值,如果存在,再计算在范围内的用户编号有多少个。

#include <iostream>
#include <vector>
#include <map>

using namespace std;

int main(int argc, char *argv[])
{
    int i, j, n, k, l, r, q, input, cnt;
    map <int, vector<int> >hobby;
    vector<int> tmp;
    
    cin >> n;
    for(i = 1; i <= n; i++)
    {
        cin >> input; //这里输入的就是所有出现的喜好值
        if(hobby.count(input) == 0) //如果喜好值没有出现过
        {
            tmp.clear();//注意这行的作用,因为某次循环中,tmp可能是上一次循环的tmp,即tmp不为空,所以要先清空
            tmp.push_back(i);
            hobby[input] = tmp;
            tmp.clear();
        }
        else
        {
            tmp = hobby[input];
            tmp.push_back(i);
            hobby[input] = tmp; //覆盖原来的键值
        }
    }
    
    cin >> q;
    while(q--)
    {
        cin >> l >> r >> k;
        cnt = 0;
        if(hobby.count(k)) //这个喜好值在map中
        {
            tmp = hobby[k];
            j = tmp.size();
            for(i = 0; i < j; i++) //计算有多少个用户编号在范围内
            {
                if(tmp[i] >= l && tmp[i] <= r)
                {
                    cnt++;
                }
            }
        }
        cout << cnt << endl;
    }
    
    return 0;
}


发表于 2019-01-26 13:39:33 回复(0)

直接在数组中进行判断有几个的,但是不知道数据大的时候,牛客上怎么就ac了,有点奇怪

import java.util.Scanner;

/**
 * @Auther: xuzhangwang
 * @Description:
 */
public class Main {
    static int[] arr;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        arr = new int[n + 1];
        for (int i = 1; i < n + 1; i++) {
            arr[i] = sc.nextInt();
        }
        int q = sc.nextInt();
        for (int i = 0; i < q; i++) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            int k = sc.nextInt();
            check(arr, l, r, k);
        }
    }

    private static void check(int[] arr, int l, int r, int k) {
        int ans = 0;
        for (int i = l; i <= r; i++) {
            if (arr[i] == k) {
                ans++;
            }
        }
        System.out.println(ans);
    }
}
发表于 2019-03-08 16:13:06 回复(0)
#include <stdio.h>
int main() {
  int n, q, low, high, key, cnt, i;
  scanf("%d", &n);
  int likes[n];
  for (i=0; i<n; ++i)
    scanf("%d", &likes[i]);
  scanf("%d", &q);
  while (q--) {
    cnt = 0;
    scanf("%d %d %d", &low, &high, &key);
    for (i=low-1; i<high; ++i)
      if (likes[i] == key)
        cnt++;
    printf("%d\n", cnt);
  }
  return 0;
}

发表于 2018-03-17 22:15:15 回复(6)
二分查找
#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n; cin >> n;
    vector<int> users(n);
    for(int i = 0; i < n; cin >> users[i++]);
    int q; cin >> q;
    vector<int> l(q), r(q), k(q);
    for(int i = 0; i < q; cin >> l[i] >> r[i] >> k[i++]);
    
    map<int, vector<int>> mp;
    for(int i = 0; i < n; ++i)
        mp[users[i]].push_back(i+1);
    
    vector<int> res(q, 0);
    for(int i = 0; i < q; ++i) {
        if(mp.count(k[i]) == 0)
            continue;
        auto pos = mp[k[i]];
        auto low = lower_bound(pos.begin(), pos.end(), l[i]);
        auto up  = upper_bound(pos.begin(), pos.end(), r[i]);
        res[i] = up - low;
    }
    
    for(int i = 0; i < q; ++i)
        cout << res[i] << endl;
}

发表于 2018-09-06 12:24:32 回复(1)
评论区的大佬们写的都好高级,但我直接搜索也完全没问题啊
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    for(int n;EOF!=scanf("%d",&n);){
        vector<int>a(n);
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        int b;
        scanf("%d",&b);
        vector<int>c(3);
        while(b--){
           // b--;
            int count=0;
            scanf("%d%d%d",&c[1],&c[2],&c[3]);
            for(int i=c[1]-1;i<=c[2]-1;i++){
                if(a[i]==c[3])count++;
            }
            printf("%d\n",count);
        }

    }
}
// 64 位输出请用 printf("%lld")

发表于 2023-06-23 17:04:07 回复(0)
importjava.util.*;
publicclassMain{
    publicstaticvoidmain(String[] args){
        Scanner sc=newScanner(System.in);
        intn=sc.nextInt();
        sc.nextLine();
        int[] arr=newint[n];
        for(inti=0;i<n;i++){
            arr[i]=sc.nextInt();
        }
        sc.nextLine();
        sc.nextInt();
        sc.nextLine();
        while(sc.hasNextLine()){
            intl=sc.nextInt()-1,r=sc.nextInt(),k=sc.nextInt();
            sc.nextLine();
            intnums=0;
            while(l<r){
                if(arr[l++]==k)
                    nums++;
            }
            System.out.println(nums);
        }
    }
}
发表于 2022-09-01 20:56:01 回复(0)
#include<bits/stdc++.h>
using namespace std;

int main(void){
    int n;    cin>> n;
    int user[n];    memset(user, 0, n*4);
    for(int i=0; i<n;i++) cin>> user[i];
    int q;    cin>> q;
    int request[q][3];
    for(int i=0; i<q;i++){
        for(int j=0; j<3;j++)
            cin>> request[i][j];
    }

    vector<int> res;
    for(int i=0; i<q;i++){
        int left = request[i][0], right=request[i][1], key = request[i][2];
        int num=0;
        for(int j=left-1; j<=right-1 ;j++){
            if(user[j] == key){
                num++;
            }
        }
        res.push_back(num);
 
    }
        
    for(auto it: res) cout<< it<<endl;
    
    return 0;
}
左右指针

发表于 2022-08-24 18:23:11 回复(0)

这道题时间限制不太行啊,我暴力也过了 (1049ms)

#include 
using namespace std;
int n, p;
int T[300005];
void solve(int l, int r, int k) {
    int cnt = 0;
    for(int i = l; i <= r; ++i) {
        if(T[i] == k) ++cnt;
    } 
    printf("%d\n", cnt);
}
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &T[i]);
    scanf("%d",&p);
    for(int  i = 0; i < p; ++i) {
        int l, r, k;
        scanf("%d%d%d", &l, &r, &k);
        solve(l, r, k);
    }
}

再来一个二分的解法,这个不如上面的快(2110ms),应该和测试用例过有关。

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <map>
using namespace std;
int n, q;
int T[300005];
int main() {
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) {
        scanf("%d", &T[i]);
    }
    map<int, vector<int>> t;
    scanf("%d", &q);
    for(int i = 0; i < q; ++i) {
        int l, r, k;
        scanf("%d%d%d", &l, &r, &k);
        if(t.find(k) == t.end()) {
            t[k] = vector<int>();
            for(int i = 0; i < n; ++i)
                if(T[i] == k)  {
                    t[k].push_back(i+1);
            //        cout << "insert " << i << endl;
                }
        }
        auto low = lower_bound(t[k].begin(), t[k].end(), l);
        auto up  = upper_bound(t[k].begin(), t[k].end(), r);
        printf("%d\n", up - low);

    }
    return 0;
}
编辑于 2022-05-15 17:06:26 回复(0)
import java.util.*;
public class Main{
    public static void main(String []args){
         Scanner sc = new Scanner(System.in);
         int n = sc.nextInt();
         int [] arr = new int[n+1];     
         for(int i = 1;i<=n;i++){
             arr[i] = sc.nextInt();
         }
         int q = sc.nextInt();     
         for(int j = 0;j<q;j++){        
            int l =sc.nextInt();
            int r =sc.nextInt();
            int k =sc.nextInt();           
            enjoy(arr,l,r,k);                                         
         }         
    }
    public static void enjoy(int [] arr,int l,int r,int k){
         int count = 0; 
         for(int m = l;m <= r;m++){  
            if(arr[m] == k) count++;                                        
         } 
         System.out.println(count);  
    }
}
发表于 2022-05-01 17:58:24 回复(1)
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext()){
            Map<Integer,Node> map=new HashMap<>();
           int n=sc.nextInt();
           for(int i=0;i<n;i++){
               int val=sc.nextInt();
               if(map.containsKey(val))
                    map.put(val,map.get(val).add(i+1));
               else
                   map.put(val,new Node(i+1));
           }
           int q=sc.nextInt();
           for(int i=0;i<q;i++){
              int l=sc.nextInt();
              int r=sc.nextInt();
              int k=sc.nextInt();
              if(!map.containsKey(k)){
                  System.out.println(0);
              }else{
                  System.out.println(map.get(k).getSize(l,r));
              }
           } 
       } 
        sc.close();
    }
} 
class Node{
    private TreeSet<Integer> set;
    public Node(int index){
        set=new TreeSet<>();
        set.add(index);
    }
    public Node add(int index){
        set.add(index);
        return this;
    }
    
    public int getSize(int l,int r){
       return set.subSet(l,true,r,true).size();
    }
} 

发表于 2021-03-24 20:26:43 回复(0)