首页 > 试题广场 >

查找重复序列

[编程题]查找重复序列
  • 热度指数:919 时间限制: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
看代码的注释就好了。应该可以看懂
注意尽量少使用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)