首页 > 试题广场 >

查找重复序列

[编程题]查找重复序列
  • 热度指数:907 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
已知某序列S=<e1,e2,…,en>,序列中的元素类型为整数(en <= 2^10),序列的长度为可变长度。
现在有若干序列S1,S2,…,Sn,现在要求设计一种算法,找出这些重复的序列。输出重复序列的序号,如果有多组重复,需全部输出。

所有序列中的数字个数加起来,小于1000000,序列个数小于10000个。

例如现有3个序列
S1=<65,43,177,655>
S2=<1,2,3,4,5,6,7>
S3=<65,43,177,655,3>
这时序列无重复。又如
S1=<65,43,177,655,3>
S2=<1,2,3,4,5,6,7>
S3=<65,43,177,655,3>
这时序列有重复。

输入描述:
第一行为一个正整数N,N>=1且N<10000

接下来为2*N数据,每两行表示一个序列,序列的第一行为序列长度L,第二行为序列的数字,一共L个


输出描述:
重复序列的序号,每一行X个数字,表示一组相同的序列,这一组相同序列共有X个,输出这X个序列的序号
示例1

输入

11
10
794 472 991 500 615 872 518 827 673 203 
1
427 
7
367 718 202 187 683 321 831 
10
1023 78 310 816 158 500 518 705 553 470 
8
205 190 306 492 166 49 791 961 
6
665 211 1009 614 15 683 
2
195 946 
3
678 198 495 
8
205 190 306 492 166 49 791 961 
5
83 74 1023 453 692 
2
176 157 

输出

4 8

Python hash解法

from collections import OrderedDict
if __name__ == '__main__':
    N = int(input())
    res = OrderedDict()
    for i in range(N):
        input()
        hash_code = hash(input())
        if hash_code in res:
            res[hash_code].append(i)
        else:
            res[hash_code] = [i]
    is_find = False
    for k, v in res.items():
        if len(v) > 1:
            is_find = True
            print(*v)
    if not is_find:
        print('no')
发表于 2020-02-20 12:38:29 回复(0)
//类比字符串哈希就行 但是可能会出现<0,0,0,0,0>和<0,0,0>的哈希值一样的情况所以  处理哈希值的时候每一步加个131就可以了
/**
**      author:XiaKIsGod
**      time:2019.9
**/
#include <bits/stdc++.h>
#define LL unsigned long long
#define pb push_back
#define endl "\n"
#define FIN freopen("1.txt","r",stdin)
#define mem(x,v) memset(x,v,sizeof(x))
#define repn(i,a,n) for(int i=a;i<=n;i++)
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
using namespace std;
inline int read() {char c;int ret = 0, sgn = 1;do { c = getchar(); } while ((c < '0' || c > '9') && c != '-');if (c == '-') sgn = -1; else ret = c - '0';while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');return sgn * ret;}
inline LL readl() {char c;LL ret = 0, sgn = 1;do { c = getchar(); } while ((c < '0' || c > '9') && c != '-');if (c == '-') sgn = -1; else ret = c - '0';while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');return sgn * ret;}
const int N = 10010;
map<LL,int> mp;
vector<int> v[N];
int main()
{
    int n = read();
    rep(i,0,n){
        int m = read();
        LL tmp = 0;
        rep(j,0,m)  tmp = tmp*2333+readl()+131;
        auto it = mp.find(tmp);
        if(it==mp.end()) mp[tmp] = i;
        else v[it->second].pb(i);
    }
    bool f = false;
    rep(i,0,n){
        if(v[i].size()>0){
            f = true;
            printf("%d ",i);
            for(auto e:v[i]) printf("%d ",e);
            printf("\n");
        }
    }
    if(!f) puts("no");
    return 0;
}


发表于 2019-09-09 18:07:44 回复(0)
这个题用python的有序表会更加方便一些。构建一个顺序表,以序列为key,以序列的编号列表作为value,在输入阶段将序列往这个顺序表里面加就行;在输出阶段直接把value长度大于1的打印出来就可以了。
from collections import OrderedDict

if __name__ == "__main__":
    n = int(input())
    m = OrderedDict()
    for i in range(n):
        L = int(input())
        seq = input().strip()
        if seq in m:
            m[seq].append(str(i))
        else:
            m[seq] = [str(i)]
    hasDuplicates = False
    for k in m:
        if len(m[k]) > 1:
            hasDuplicates = True
            print(" ".join(m[k]))
    if not hasDuplicates:
        print("no")

发表于 2021-12-06 21:10:21 回复(0)
使用map, vector<int>为键,vector<int>为值
详见代码
坑点(题目未指明输出格式):如果有多组答案,输出按照每一组的第一个数字排序

#include<iostream>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;


int main() {
	int n;
	scanf("%d", &n);
	map<vector<int>, vector<int>>mp;
	for (int i = 0; i < n; i++) {
		vector<int>vec;
		int k;
		scanf("%d", &k);
		while (k--) {
			int x;
			scanf("%d", &x);
			vec.push_back(x);
		}
		mp[vec].push_back(i);
	}
	bool flag = false;
	vector<vector<int>>ans;
	for (auto v : mp) {
		if (v.second.size() > 1) {
			flag = true;
			ans.push_back(v.second);
		}
	}
	sort(ans.begin(), ans.end(), [](vector<int>& lhs, vector<int>& rhs)->bool {
		if (lhs.size() != 0 && rhs.size() != 0) return lhs[0] < rhs[0];
		else return lhs.size() < rhs.size();
		});
	for (auto v : ans) {
		for (int i = 0; i < v.size(); i++) {
			printf("%s%d", i ? " " : "", v[i]);
		}
		printf("\n");
	}
	if (!flag) printf("no");
	return 0;
}


发表于 2020-10-11 16:09:39 回复(0)
看代码的注释就好了。应该可以看懂
注意尽量少使用System.out.print或者System.out.println的次数。使用一次是很耗时的。
我最开始的时候,满足条件的相同序列输出要三次使用System.out.print或者System.out.println
下面隐去的三个System.out.print或者System.out.println就是。测试报超时。
后来改成了用StringBuilder来保存结果,最后一次输出就好。顺利通过。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

public class Main {

    //判断两个list是否相同
    public static boolean sameArr(List<Integer> list1, List<Integer> list2) {
        if (list1.size() != list2.size()) {
            return false;
        } else {
            for (int i = 0; i < list1.size(); i++) {
                if (!(list1.get(i).equals(list2.get(i))))
                    return false;
            }
            return true;
        }
    }

    public static void sameSet(List<List<Integer>> list) {
        //这个set用来去重。假如i=2,3,8时三个序列相同。那么只需要遍历i=2时就好了 ,i=3和i=8的时候直接跳过
        Set<Integer> set = new TreeSet<Integer>();
        int isHave = 0;
        //这个isHave用来表示整个List<List<Integer>> list是否用相同的序列
        for (int i = 0; i < list.size() - 1; i++) {
            int flag = 0;
            // 这个flag用来表示 是否有与list.get(i)相同的序列
            if (set.contains(i)) {
                continue;
            }
            StringBuilder builder = new StringBuilder();
            //这个builder用于保存满足条件的一次输出结果,一次循环结束之后,输出就可以了。
            // 下面隐去的三个System.out.print就是我最开始的输出方式。但是测试的时候超时了。使用System.out.print需要进行各种切换,保护现场以及恢复现场,非常耗时
            //后来就想到用builder保存结果,使用一次System.out.print。速度快了很多,顺利通过。
            for (int j = i + 1; j < list.size(); j++) {
                if (sameArr(list.get(i), list.get(j)) && flag == 0) {
                    //注意这个if条件和下面那个if条件的区别,这个表示第一次有序列与list.get(i)相同,那么i和j必须都加进去
                    builder.append(i+" "+j);
                    // System.out.print(i + " " + j);
                    flag++;
                    isHave++;
                    set.add(i);
                    set.add(j);
                    continue;
                }
                if (flag != 0 && sameArr(list.get(i), list.get(j))) {
                    //进入这个循环表明至少有两个序列和list.get(i)相同,因为第一次加了i,所以只的每一场只需要加j就好了
                     builder.append(" "+j);
                    // System.out.print(" " + j);
                    set.add(j);
                }
            }
            if (flag != 0) {
                //System.out.println();
                System.out.println(builder.toString());
            }
        }
        if (isHave == 0) {
            System.out.println("no");
        }
    }

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        List<List<Integer>> list = new ArrayList<List<Integer>>();
        while (in.hasNextInt()) {
            int num = in.nextInt();
            List<Integer> tmp = new ArrayList<Integer>();
            for (int i = 0; i < num; i++) {
                int n = in.nextInt();
                tmp.clear();
                for (int j = 0; j < n; j++) {
                    tmp.add(in.nextInt());
                }
                list.add(new ArrayList<Integer>(tmp));
            }
            sameSet(list);
            list.clear();
        }
    }
}
编辑于 2019-08-09 17:21:53 回复(0)
😌这题的测试用例是不是数据输入不够...那个102组数据的用例我copy下来在IDE上用istringstream输入只有34组数据...
发表于 2019-07-26 17:25:06 回复(2)
#include <string>
#include <unordered_map>
#include <vector>
#include <iostream>
using namespace std;
vector<string> arr;
unordered_map<int, bool> map;
int main() {
    int n, m, num;
    bool flag = false;
    cin >> n;
    for (int i = 0; i < n; i++) {
        string s;
        cin >> m;
        for (int j = 0; j < m; j++) {
            cin >> num;
            s += to_string(num);
        }
        arr.push_back(s);
    }
    for (int i = 0; i < arr.size() - 1; i++) {
        if (map.find(i) != map.end())
            continue;
        vector<int> res;
        res.push_back(i);
        for (int j = i + 1; j < arr.size(); j++) {
            if (map.find(j) != map.end())
                continue;
            if (arr[i] == arr[j]) {
                res.push_back(j);
                map[i] = true;
                map[j] = true;
            }
        }
        if (res.size() > 1) {
            flag = true;
            for (int k = 0; k < res.size(); k++) {
                cout << res[k] << " ";
            }
            cout << "" << endl;
        }
    }
    if (!flag)
        cout << "no" << endl;
    return 0;

}
// 64 位输出请用 printf("%lld")
//我尝试将数组序列转换成字符串,然后再去比较,但是有两个测试示例不能通过,希望有小伙伴帮忙看一下


发表于 2023-09-06 00:19:24 回复(0)
import sys

if __name__ == "__main__":
    N = int(sys.stdin.readline().strip())
    data_list = []
    unique_dict = {}

    for i in range(N):
        L = sys.stdin.readline().strip()
        data_list.append(tuple(map(int, sys.stdin.readline().strip().split(" "))))
    res = []
    for i in range(N):
        if data_list[i] not in unique_dict:
            unique_dict[data_list[i]] = [i]  # 将序列作为key,下标作为value
        else:
            unique_dict[data_list[i]].append(i)
    flag = True
    for key, value in unique_dict.items():
        # 找出重复的序列,将其下标添加到res中
        if len(value) > 1:
            flag = False
            res.append(value)

    if flag:
        print("no")
    else:
        res.sort()  # 结果对目标有排序要求,因此将unique_dict中的value进行排序,在输出
        for value in res:
            tmp = [str(j) for j in value]
            print(' '.join(tmp))


发表于 2020-06-19 16:26:16 回复(0)
import java.util.*;
 
public class Main {
    public static void main(String[] args) {
        run();
    }
     
    public static void run(){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine();
        HashMap<String,List<Integer>> amap = new HashMap<String, List<Integer>>();
        for(int i=0;i<n;i++){
                int m = sc.nextInt();sc.nextLine();
                String t = sc.nextLine();
                List<Integer> a = new ArrayList<>();
                if(amap.containsKey(t)){
                     a = amap.get(t);
                }
                a.add(i);
                amap.put(t, a);
//          }
        }
//      int tmp = 0;
        TreeMap<Integer,List<Integer>> re = new TreeMap<Integer, List<Integer>>();
        for(String k:amap.keySet()){
            List<Integer> a = amap.get(k);
            if(a.size()>1){
                re.put(a.get(0), a);
            }
        }
        for(int i:re.keySet()){
            List<Integer> a = re.get(i);
            for(int j:a){
                System.out.print(j+" ");
            }
            System.out.println();
        }
        if(re.size()<1){
            System.out.println("no");
        }
    }
}
我的方法是从序列本身出发的,不需要比较多个序列是否重复。
用HashMap存 所有序列,以及它们处应的序号。
发表于 2019-09-18 00:35:52 回复(0)
Python 字典树
先对输入做长度排序,长度不一致的肯定不会一样
对相同排序的集群做字典树
这输出有毒,我是没法整了,答案只是排序不一样,调了好久,不算我过
算一种参考思路吧
import sys

if __name__ == '__main__':
    S = []
    S_len = []
    N = int(sys.stdin.readline().strip())
    for i in range(N):
        n = int(sys.stdin.readline().strip())
        S.append(list(map(int, sys.stdin.readline().split())))
        S_len.append((i, n))
    S_len.sort(key=lambda x:x[1])
    cur_len = S_len[0][1]

    global_dic = {}
    res_dic = {}
    for i in range(N):
        if S_len[i][1] > cur_len:
            t = {}
            global_dic = t
            for val in S[S_len[i][0]]:
                t[val] = {}
                t = t[val]
            t['end'] = str(S_len[i][0])
            cur_len = S_len[i][1]
        else:
            t = global_dic
            for val in S[S_len[i][0]]:
                if t.get(val,False):
                    t = t[val]
                else:
                    t[val] = {}
                    t = t[val]
            if t.get('end', False):
                if res_dic.get(t['end'], False):
                    res_dic[t['end']].append(str(S_len[i][0]))
                else:
                    res_dic[t['end']] = [t['end'], str(S_len[i][0])]
            else:
                t['end'] = str(S_len[i][0])

    if not res_dic:
        print('no')
    else:
        for res in sorted(list(res_dic.values()), key=lambda x:x[0]):
            sys.stdout.write(' '.join(res)+'\n')


发表于 2019-09-02 21:32:08 回复(0)
#include<iostream>
#include<vector>
#include<list>
#include<unordered_map>
#include<algorithm>
using namespace std;
 
struct ArrayProxy{
    ArrayProxy(vector<vector<int>>& arr, int idx)
        : mIdx(idx)
        , mSum(std::accumulate(arr[idx].begin(), arr[idx].end(), 0))
        , mLen(static_cast<int>(arr[idx].size()))
        , mArray(&arr) {
             
    }
public:
    int mIdx;
    int mSum;
    int mLen;
    vector<vector<int>>* mArray;
};
 
struct ArrayProxyHash{
    size_t operator()(const ArrayProxy& arrproxy) const noexcept{
        return arrproxy.mSum;
    }
};
 
struct ArrayProxyEqual{
    bool operator()(const ArrayProxy& lhs, const ArrayProxy& rhs) const{
        if(lhs.mSum != rhs.mSum || lhs.mLen != rhs.mLen)
            return false;
        int len = lhs.mLen;
        vector<int>& larr = (*(lhs.mArray))[lhs.mIdx];
        vector<int>& rarr = (*(rhs.mArray))[rhs.mIdx];
        for(int i = 0; i < len; ++i){
            if(larr[i] != rarr[i])
                return false;
        }
        return true;
    }
};
 
int main(){
    int N; cin >> N;
    vector<vector<int>> nums(N);
    for(int i = 0; i < N; ++i){
        int len; cin >> len;
        vector<int> arr(len);
        for(int j = 0; j < len; ++j)
            cin >> arr[j];
        nums[i].swap(arr);
    }
    vector<list<int>> colli(N);
    unordered_map<ArrayProxy, 
                  int, 
                  ArrayProxyHash, 
                  ArrayProxyEqual>  hash;
    for(int i = 0; i < N; ++i){
        ArrayProxy aproxy(nums, i);
        if(hash.count(aproxy))
            colli[hash[aproxy]].push_back(i);
        else
            hash[aproxy] = i;
    }
    int k = 0;
    for(int i = 0; i < N; ++i){
        if(colli[i].empty()){
            ++k;
            continue;
        }
        cout << i << ' ';
        for(auto iter = colli[i].begin(); iter != colli[i].end(); ++iter)
            cout << *iter << ' ';
        cout << '\n';
    }
    if(k == N) cout << "no\n";
    return 0;
}

发表于 2019-08-06 13:44:54 回复(0)
n = int(input())
seqs = []
for i in range(n):
    length  = int(input())

    seqs.append(tuple(map(int,input().split())))
dic  = {}
out = [[] for i in range(n)]
for i in range(len(seqs)):
    if seqs[i] not in dic:
        dic[seqs[i]] = i
    else:
        tmp = []
        # out.append(i)
        if dic[seqs[i]] not in out[dic[seqs[i]]]:
            out[dic[seqs[i]]].append(dic[seqs[i]])
            # out.append(dic[seqs[i]])


        out[dic[seqs[i]]].append(i)
if out == [[] for i in range(n)]:
    print('no')
else:

    for line in out:
        if line !=[]:
            print(' '.join([str(x) for x in line]))

暴力循环超时,使用dic来判断是否出现过,若出现则插入到相应行。
发表于 2019-08-01 17:27:20 回复(0)